Skip to content

Commit

Permalink
Feature: Add pinned items to taskbar jumplist (#11632)
Browse files Browse the repository at this point in the history
  • Loading branch information
hecksmosis authored Mar 12, 2023
1 parent ec17cd8 commit bdf6a81
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 19 deletions.
11 changes: 10 additions & 1 deletion src/Files.App/DataModels/SidebarPinnedModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Files.App.Filesystem;
using Files.App.Helpers;
using Files.App.ServicesImplementation;
using Files.App.UserControls.Widgets;
using Files.Backend.Services.Settings;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -193,7 +194,15 @@ public void RemoveStaleSidebarItems()
}

public async void LoadAsync(object? sender, FileSystemEventArgs e)
=> await LoadAsync();
{
App.QuickAccessManager.PinnedItemsWatcher.EnableRaisingEvents = false;
await LoadAsync();
App.QuickAccessManager.UpdateQuickAccessWidget?.Invoke(null, new ModifyQuickAccessEventArgs((await QuickAccessService.GetPinnedFoldersAsync()).Select(x => x.FilePath).ToArray(), true)
{
Reset = true
});
App.QuickAccessManager.PinnedItemsWatcher.EnableRaisingEvents = true;
}

public async Task LoadAsync()
=> await UpdateItemsWithExplorer();
Expand Down
52 changes: 34 additions & 18 deletions src/Files.App/Helpers/JumpListManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Files.App.Filesystem;
using Files.App.UserControls.Widgets;
using Files.Shared.Extensions;
using System;
using System.Collections.Generic;
Expand All @@ -14,6 +15,8 @@ public sealed class JumpListManager
{
private JumpList instance = null;
private List<string> JumpListItemPaths { get; set; }
private readonly string JumpListRecentGroupHeader = "ms-resource:///Resources/JumpListRecentGroupHeader";
private readonly string JumpListPinnedGroupHeader = "ms-resource:///Resources/JumpListPinnedGroupHeader";

public JumpListManager()
{
Expand All @@ -27,6 +30,9 @@ public async Task InitializeAsync()
if (JumpList.IsSupported())
{
instance = await JumpList.LoadCurrentAsync();
App.QuickAccessManager.UpdateQuickAccessWidget += QuickAccessManager_DataChanged;

QuickAccessManager_DataChanged(null, null);

// Disable automatic jumplist. It doesn't work with Files UWP.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
Expand All @@ -48,14 +54,14 @@ public async void AddFolderToJumpList(string path)
{
if (instance is not null)
{
AddFolder(path);
AddFolder(path, JumpListRecentGroupHeader);
await instance.SaveAsync();
}
}
catch { }
}

private void AddFolder(string path)
private void AddFolder(string path, string group)
{
if (instance is not null)
{
Expand All @@ -65,9 +71,7 @@ private void AddFolder(string path)
// Jumplist item argument can't end with a slash so append a character that can't exist in a directory name to support listing drives.
var drive = App.DrivesManager.Drives.Where(drive => drive.Path == path).FirstOrDefault();
if (drive is null)
{
return;
}

displayName = drive.Text;
path += '?';
Expand All @@ -76,13 +80,9 @@ private void AddFolder(string path)
if (displayName is null)
{
if (path.Equals(CommonPaths.DesktopPath, StringComparison.OrdinalIgnoreCase))
{
displayName = "ms-resource:///Resources/Desktop";
}
else if (path.Equals(CommonPaths.DownloadsPath, StringComparison.OrdinalIgnoreCase))
{
displayName = "ms-resource:///Resources/Downloads";
}
else if (path.Equals(CommonPaths.RecycleBinPath, StringComparison.OrdinalIgnoreCase))
{
var localSettings = ApplicationData.Current.LocalSettings;
Expand All @@ -108,21 +108,28 @@ private void AddFolder(string path)
}
}
else
{
displayName = Path.GetFileName(path);
}
}

var jumplistItem = JumpListItem.CreateWithArguments(path, displayName);
jumplistItem.Description = jumplistItem.Arguments;
jumplistItem.GroupName = "ms-resource:///Resources/JumpListRecentGroupHeader";
jumplistItem.GroupName = group;
jumplistItem.Logo = new Uri("ms-appx:///Assets/FolderIcon.png");

// Keep newer items at the top.
instance.Items.Remove(instance.Items.FirstOrDefault(x => x.Arguments.Equals(path, StringComparison.OrdinalIgnoreCase)));
instance.Items.Insert(0, jumplistItem);
JumpListItemPaths.Remove(JumpListItemPaths.FirstOrDefault(x => x.Equals(path, StringComparison.OrdinalIgnoreCase)));
JumpListItemPaths.Add(path);
if (string.Equals(group, JumpListRecentGroupHeader, StringComparison.OrdinalIgnoreCase))
{
// Keep newer items at the top.
instance.Items.Remove(instance.Items.FirstOrDefault(x => x.Arguments.Equals(path, StringComparison.OrdinalIgnoreCase)));
instance.Items.Insert(0, jumplistItem);

JumpListItemPaths.Remove(JumpListItemPaths.FirstOrDefault(x => x.Equals(path, StringComparison.OrdinalIgnoreCase)));
JumpListItemPaths.Add(path);
}
else
{
var pinnedItemsCount = instance.Items.Where(x => x.GroupName == JumpListPinnedGroupHeader).Count();
instance.Items.Insert(pinnedItemsCount, jumplistItem);
}
}
}

Expand All @@ -133,9 +140,7 @@ public async void RemoveFolder(string path)
try
{
if (instance is null)
{
return;
}

if (JumpListItemPaths.Remove(path))
{
Expand All @@ -146,5 +151,16 @@ public async void RemoveFolder(string path)
}
catch { }
}

private async void QuickAccessManager_DataChanged(object sender, ModifyQuickAccessEventArgs e)
{
if (instance is null)
return;

var itemsToRemove = instance.Items.Where(x => string.Equals(x.GroupName, JumpListPinnedGroupHeader, StringComparison.OrdinalIgnoreCase)).ToList();
itemsToRemove.ForEach(x => instance.Items.Remove(x));
App.QuickAccessManager.Model.FavoriteItems.ForEach(x => AddFolder(x, JumpListPinnedGroupHeader));
await instance.SaveAsync();
}
}
}
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 @@ -2610,4 +2610,7 @@
<data name="UnableToCalcHashes" xml:space="preserve">
<value>Unable to calculate hashes due to a system error</value>
</data>
<data name="JumpListPinnedGroupHeader" xml:space="preserve">
<value>Pinned items</value>
</data>
</root>
38 changes: 38 additions & 0 deletions src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Files.App.ViewModels;
using Files.App.ViewModels.Widgets;
using Files.Backend.Services.Settings;
using Files.Shared;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
Expand Down Expand Up @@ -39,14 +40,23 @@ public class QuickAccessCardInvokedEventArgs : EventArgs
public class ModifyQuickAccessEventArgs : EventArgs
{
public string[] Paths { get; set; }
public ShellFileItem[] Items { get; set; }
public bool Add;
public bool Pin = true;
public bool Reset = false;

public ModifyQuickAccessEventArgs(string[] paths, bool add)
{
Paths = paths;
Add = add;
}

public ModifyQuickAccessEventArgs(ShellFileItem[] items, bool add)
{
Paths = items.Select(x => x.FilePath).ToArray();
Items = items;
Add = add;
}
}

public class FolderCardItem : WidgetCardItem, IWidgetCardItem<LocationItem>
Expand Down Expand Up @@ -237,6 +247,34 @@ private async void ModifyItem(object? sender, ModifyQuickAccessEventArgs? e)

await DispatcherQueue.EnqueueAsync(async () =>
{
if (e.Reset)
{
// Find the intersection between the two lists and determine whether to remove or add
var itemsToRemove = ItemsAdded.Where(x => !e.Paths.Contains(x.Path)).ToList();
var itemsToAdd = e.Paths.Where(x => !ItemsAdded.Any(y => y.Path == x)).ToList();

// Remove items
foreach (var itemToRemove in itemsToRemove)
ItemsAdded.Remove(itemToRemove);

// Add items
foreach (var itemToAdd in itemsToAdd)
{
var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd);
var lastIndex = ItemsAdded.IndexOf(ItemsAdded.FirstOrDefault(x => !x.IsPinned));
var isPinned = (bool?)e.Items.Where(x => x.FilePath == itemToAdd).FirstOrDefault().Properties["System.Home.IsPinned"] ?? false;

ItemsAdded.Insert(isPinned && lastIndex >= 0 ? lastIndex : ItemsAdded.Count, new FolderCardItem(item, Path.GetFileName(item.Text), isPinned)
{
Path = item.Path,
SelectCommand = QuickAccessCardCommand
});
}
var cardLoadTasks = ItemsAdded.Select(cardItem => cardItem.LoadCardThumbnailAsync());
await Task.WhenAll(cardLoadTasks);

return;
}
if (e.Add)
{
foreach (var itemToAdd in e.Paths)
Expand Down

0 comments on commit bdf6a81

Please sign in to comment.