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

Feature: Option to open all items in a tag #11598

Closed
Show file tree
Hide file tree
Changes from all commits
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
34 changes: 34 additions & 0 deletions src/Files.App/Actions/Content/Tags/OpenAllTaggedAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Helpers;
using Files.Shared.Extensions;
using System.Linq;
using System.Threading.Tasks;

namespace Files.App.Actions.Content.Tags
{
internal class OpenAllTaggedAction : IAction
{
private readonly ITagsContext tagsContext = Ioc.Default.GetRequiredService<ITagsContext>();

private readonly IContentPageContext pageContext = Ioc.Default.GetRequiredService<IContentPageContext>();

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

public RichGlyph Glyph { get; } = new("\uE8E5");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which icon is this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a temp icon since OpacityIcon is not working
1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try &#xE71D;?


public async Task ExecuteAsync()
{
if (pageContext.ShellPage is null)
return;

var files = tagsContext.TaggedItems.Where(taggedItem => !taggedItem.IsFolder);
var folders = tagsContext.TaggedItems.Where(taggedItem => taggedItem.IsFolder);

await Task.WhenAll(files.Select(file => NavigationHelpers.OpenPath(file.Path, pageContext.ShellPage)));
folders.ForEach(async folder => await NavigationHelpers.OpenPathInNewTab(folder.Path));
}
}
}
4 changes: 3 additions & 1 deletion src/Files.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ private IServiceProvider ConfigureServices()
.AddSingleton<IPageContext, PageContext>()
.AddSingleton<IContentPageContext, ContentPageContext>()
.AddSingleton<IDisplayPageContext, DisplayPageContext>()

.AddSingleton<ITagsContext, TagsContext>()

// Other services
.AddSingleton(Logger)
.AddSingleton<IDialogService, DialogService>()
Expand All @@ -137,6 +138,7 @@ private IServiceProvider ConfigureServices()
.AddSingleton<ICloudDetector, CloudDetector>()
.AddSingleton<IFileTagsService, FileTagsService>()
.AddSingleton<ICommandManager, CommandManager>()

#if UWP
.AddSingleton<IStorageService, WindowsStorageService>()
#else
Expand Down
3 changes: 3 additions & 0 deletions src/Files.App/Commands/CommandCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public enum CommandCodes
// Image Edition
RotateLeft,
RotateRight,

// Tags
OpenAllTaggedItems,

// Navigation
NewTab,
Expand Down
3 changes: 3 additions & 0 deletions src/Files.App/Commands/Manager/CommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Files.App.Actions;
using Files.App.Actions.Content.Archives;
using Files.App.Actions.Content.Background;
using Files.App.Actions.Content.Tags;
using Files.App.Actions.Content.ImageEdition;
using Files.App.Actions.Favorites;
using Microsoft.UI.Xaml;
Expand Down Expand Up @@ -60,6 +61,7 @@ internal class CommandManager : ICommandManager
public IRichCommand CompressIntoZip => commands[CommandCodes.CompressIntoZip];
public IRichCommand RotateLeft => commands[CommandCodes.RotateLeft];
public IRichCommand RotateRight => commands[CommandCodes.RotateRight];
public IRichCommand OpenAllTaggedItems => commands[CommandCodes.OpenAllTaggedItems];
public IRichCommand NewTab => commands[CommandCodes.NewTab];
public IRichCommand DuplicateTab => commands[CommandCodes.DuplicateTab];

Expand Down Expand Up @@ -122,6 +124,7 @@ public CommandManager()
[CommandCodes.CompressIntoZip] = new CompressIntoZipAction(),
[CommandCodes.RotateLeft] = new RotateLeftAction(),
[CommandCodes.RotateRight] = new RotateRightAction(),
[CommandCodes.OpenAllTaggedItems] = new OpenAllTaggedAction(),
[CommandCodes.NewTab] = new NewTabAction(),
[CommandCodes.DuplicateTab] = new DuplicateTabAction(),
};
Expand Down
2 changes: 2 additions & 0 deletions src/Files.App/Commands/Manager/ICommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public interface ICommandManager : IEnumerable<IRichCommand>

IRichCommand RotateLeft { get; }
IRichCommand RotateRight { get; }

IRichCommand OpenAllTaggedItems { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing looks off


IRichCommand NewTab { get; }
IRichCommand DuplicateTab { get; }
Expand Down
10 changes: 10 additions & 0 deletions src/Files.App/Contexts/Tags/ITagsContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Files.App.ViewModels.Widgets;
using System.Collections.Generic;

namespace Files.App.Contexts
{
public interface ITagsContext
{
IEnumerable<FileTagsItemViewModel> TaggedItems { get; set; }
}
}
25 changes: 25 additions & 0 deletions src/Files.App/Contexts/Tags/TagsContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Files.App.ViewModels.Widgets;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace Files.App.Contexts
{
internal class TagsContext : ITagsContext
{
private static readonly IReadOnlyList<FileTagsItemViewModel> emptyTaggedItemsList = Enumerable.Empty<FileTagsItemViewModel>().ToImmutableList();

private IEnumerable<FileTagsItemViewModel> taggedItems = emptyTaggedItemsList;
public IEnumerable<FileTagsItemViewModel> TaggedItems
{
get => taggedItems;
set
{
if (value is not null)
taggedItems = value;
else
taggedItems = emptyTaggedItemsList;
}
}
}
}
3 changes: 3 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2595,6 +2595,9 @@
<data name="MultiSelect" xml:space="preserve">
<value>Multiselect</value>
</data>
<data name="OpenAllItems" xml:space="preserve">
<value>Open all</value>
</data>
<data name="Hashes" xml:space="preserve">
<value>Hashes</value>
</data>
Expand Down
30 changes: 21 additions & 9 deletions src/Files.App/UserControls/Widgets/FileTagsWidget.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,29 @@
</Grid.RowDefinitions>

<!-- Title -->
<StackPanel
<Grid
Grid.Row="0"
Padding="12,8"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="0,0,0,1"
Orientation="Horizontal"
Spacing="8">
ColumnSpacing="8"
RightTapped="TagTitle_RightTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Ellipse
Width="12"
Height="12"
Fill="{x:Bind Color, Mode=OneWay, Converter={StaticResource StringToBrushConverter}}" />
<TextBlock
Grid.Column="1"
Margin="0,-2,0,0"
HorizontalAlignment="Stretch"
FontWeight="SemiBold"
Text="{x:Bind Name, Mode=OneWay}" />
</StackPanel>
</Grid>

<!-- Contents -->
<controls:AdaptiveGridView
Expand All @@ -89,11 +96,15 @@

<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="vm:FileTagsItemViewModel">
<StackPanel
<Grid
ColumnSpacing="8"
DataContext="{x:Bind}"
Orientation="Horizontal"
RightTapped="Item_RightTapped"
Spacing="8">
RightTapped="Item_RightTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<!-- Icon -->
<Image
Width="20"
Expand All @@ -103,10 +114,11 @@

<!-- Name -->
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Name, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
</StackPanel>
</Grid>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
Expand Down
72 changes: 59 additions & 13 deletions src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.UI;
using CommunityToolkit.WinUI.UI.Controls;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Filesystem;
using Files.App.Helpers;
using Files.App.Helpers.ContextFlyouts;
using Files.App.ViewModels;
using Files.App.ViewModels.Widgets;
using Files.App.Views;
using Files.Backend.Services.Settings;
using Files.Shared.Extensions;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
Expand All @@ -22,8 +22,6 @@
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.Storage;
using Windows.System;
using Windows.UI.Core;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

Expand All @@ -39,6 +37,10 @@ public FileTagsWidgetViewModel ViewModel

private readonly IUserSettingsService userSettingsService = Ioc.Default.GetRequiredService<IUserSettingsService>();

private readonly ICommandManager commands = Ioc.Default.GetRequiredService<ICommandManager>();

private readonly ITagsContext tagsContext = Ioc.Default.GetRequiredService<ITagsContext>();

public IShellPage AppInstance;
public Func<string, Task>? OpenAction { get; set; }

Expand Down Expand Up @@ -110,16 +112,50 @@ private async void FileTagItem_ItemClick(object sender, ItemClickEventArgs e)
await itemViewModel.ClickCommand.ExecuteAsync(null);
}

private async void Item_RightTapped(object sender, RightTappedRoutedEventArgs e)
private void TagTitle_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (sender is not Grid grid || grid.Parent is not Grid parent)
return;

LoadContextMenuItem(parent, e, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to create the menu in xaml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, anyway I'll mark this as Draft and I'll change this once we have a final context, to avoid working twice

}

private void Item_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
App.Logger.Warn("rightTapped");
if (sender is not Grid tagsItemsGrid)
return;

LoadContextMenuItem(tagsItemsGrid, e);
}

private async void LoadContextMenuItem(Grid contextGrid, RightTappedRoutedEventArgs e, bool isWidgetMenu = false)
{
List<ContextMenuFlyoutItemViewModel> menuItems;
FileTagsItemViewModel? selectedItem = null;

if (isWidgetMenu)
{
if (contextGrid.Children[1] is not AdaptiveGridView gridView)
return;

var items = gridView.Items.Select(item => (FileTagsItemViewModel)item);

tagsContext.TaggedItems = items;
menuItems = GetWidgetMenuItems();
}
else
{
if (contextGrid.DataContext is not FileTagsItemViewModel item)
return;

selectedItem = item;
menuItems = GetItemMenuItems(item, QuickAccessService.IsItemPinned(item.Path), item.IsFolder);
}


var itemContextMenuFlyout = new CommandBarFlyout { Placement = FlyoutPlacementMode.Full };
itemContextMenuFlyout.Opening += (sender, e) => App.LastOpenedFlyout = sender as CommandBarFlyout;
if (sender is not StackPanel tagsItemsStackPanel || tagsItemsStackPanel.DataContext is not FileTagsItemViewModel item)
return;

App.Logger.Warn("Item path: " + item.Path + " widgetcarditem.path = " + (item as WidgetCardItem)?.Path);
var menuItems = GetItemMenuItems(item, QuickAccessService.IsItemPinned(item.Path), item.IsFolder);
var (_, secondaryElements) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(menuItems);

if (!UserSettingsService.PreferencesSettingsService.MoveShellExtensionsToSubMenu)
Expand All @@ -128,9 +164,11 @@ private async void Item_RightTapped(object sender, RightTappedRoutedEventArgs e)

secondaryElements.ForEach(i => itemContextMenuFlyout.SecondaryCommands.Add(i));
ItemContextMenuFlyout = itemContextMenuFlyout;
itemContextMenuFlyout.ShowAt(tagsItemsStackPanel, new FlyoutShowOptions { Position = e.GetPosition(tagsItemsStackPanel) });
itemContextMenuFlyout.ShowAt(contextGrid, new FlyoutShowOptions { Position = e.GetPosition(contextGrid) });

if (selectedItem is not null)
await ShellContextmenuHelper.LoadShellMenuItems(selectedItem.Path, itemContextMenuFlyout, showOpenWithMenu: true, showSendToMenu: true);

await ShellContextmenuHelper.LoadShellMenuItems(item.Path, itemContextMenuFlyout, showOpenWithMenu: true, showSendToMenu: true);
e.Handled = true;
}

Expand Down Expand Up @@ -240,6 +278,14 @@ public override List<ContextMenuFlyoutItemViewModel> GetItemMenuItems(WidgetCard
}.Where(x => x.ShowItem).ToList();
}

public List<ContextMenuFlyoutItemViewModel> GetWidgetMenuItems()
{
return new List<ContextMenuFlyoutItemViewModel>()
{
new ContextMenuFlyoutItemViewModelBuilder(commands.OpenAllTaggedItems).Build()
};
}

public void OpenFileLocation(WidgetCardItem? item)
{
FileTagsOpenLocationInvoked?.Invoke(this, new PathNavigationEventArgs()
Expand Down