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: Add pinned items to taskbar jumplist #11632

Merged
merged 10 commits into from
Mar 12, 2023
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(FavoriteItems.ToArray(), true)
{
Reset = true
});
App.QuickAccessManager.PinnedItemsWatcher.EnableRaisingEvents = true;
}

public async Task LoadAsync()
=> await UpdateItemsWithExplorer();
Expand Down
50 changes: 32 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 Down Expand Up @@ -27,6 +28,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 +52,14 @@ public async void AddFolderToJumpList(string path)
{
if (instance is not null)
{
AddFolder(path);
AddFolder(path, "ms-resource:///Resources/JumpListRecentGroupHeader");
await instance.SaveAsync();
hecksmosis marked this conversation as resolved.
Show resolved Hide resolved
}
}
catch { }
}

private void AddFolder(string path)
private void AddFolder(string path, string group)
{
if (instance is not null)
{
Expand All @@ -65,9 +69,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 +78,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 +106,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, "ms-resource:///Resources/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 == "ms-resource:///Resources/JumpListPinnedGroupHeader").Count();
instance.Items.Insert(pinnedItemsCount, jumplistItem);
}
}
}

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

if (JumpListItemPaths.Remove(path))
{
Expand All @@ -146,5 +149,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, "ms-resource:///Resources/JumpListPinnedGroupHeader", StringComparison.OrdinalIgnoreCase)).ToList();
itemsToRemove.ForEach(x => instance.Items.Remove(x));
App.QuickAccessManager.Model.FavoriteItems.ForEach(x => AddFolder(x, "ms-resource:///Resources/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>
33 changes: 33 additions & 0 deletions src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,19 @@ public class ModifyQuickAccessEventArgs : EventArgs
public string[] Paths { 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()
{
Paths = Array.Empty<string>();
Add = false;
}
}

public class FolderCardItem : WidgetCardItem, IWidgetCardItem<LocationItem>
Expand Down Expand Up @@ -237,6 +244,32 @@ 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));
ItemsAdded.Insert(e.Pin && lastIndex >= 0 ? lastIndex : ItemsAdded.Count, new FolderCardItem(item, Path.GetFileName(item.Text), e.Pin)
{
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