-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Expand file tree
/
Copy pathWindowsJumpListService.cs
More file actions
217 lines (190 loc) · 6.68 KB
/
Copy pathWindowsJumpListService.cs
File metadata and controls
217 lines (190 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.Extensions.Logging;
using System.IO;
using Windows.UI.StartScreen;
namespace Files.App.Services
{
public sealed class WindowsJumpListService : IWindowsJumpListService
{
private const string JumpListRecentGroupHeader = "ms-resource:///Resources/JumpListRecentGroupHeader";
private const string JumpListPinnedGroupHeader = "ms-resource:///Resources/JumpListPinnedGroupHeader";
public async Task InitializeAsync()
{
try
{
App.QuickAccessManager.UpdateQuickAccessWidget -= UpdateQuickAccessWidget_Invoked;
App.QuickAccessManager.UpdateQuickAccessWidget += UpdateQuickAccessWidget_Invoked;
await RefreshPinnedFoldersAsync();
}
catch (Exception ex)
{
App.Logger.LogWarning(ex, ex.Message);
}
}
public async Task AddFolderAsync(string path)
{
try
{
if (JumpList.IsSupported())
{
var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
// Saving to jumplist may fail randomly with error: ERROR_UNABLE_TO_REMOVE_REPLACED
// In that case app should just catch the error and proceed as usual
if (instance is not null)
{
AddFolder(path, JumpListRecentGroupHeader, instance);
await instance.SaveAsync();
}
}
}
catch (Exception ex)
{
App.Logger.LogWarning(ex, ex.Message);
}
}
public async Task<IEnumerable<string>> GetFoldersAsync()
{
if (JumpList.IsSupported())
{
try
{
var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
return instance.Items.Select(item => item.Arguments).ToList();
}
catch
{
return [];
}
}
else
{
return [];
}
}
public async Task RefreshPinnedFoldersAsync()
{
try
{
if (App.QuickAccessManager.PinnedItemsWatcher is not null)
App.QuickAccessManager.PinnedItemsWatcher.EnableRaisingEvents = false;
if (JumpList.IsSupported())
{
var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work with Files UWP.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
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.PinnedFolders.ForEach(x => AddFolder(x, JumpListPinnedGroupHeader, instance));
await instance.SaveAsync();
}
}
catch
{
}
finally
{
if (App.QuickAccessManager.PinnedItemsWatcher is not null)
SafetyExtensions.IgnoreExceptions(() => App.QuickAccessManager.PinnedItemsWatcher.EnableRaisingEvents = true);
}
}
public async Task RemoveFolderAsync(string path)
{
await RemoveFoldersAsync([path]);
}
/// <inheritdoc/>
public async Task RemoveFoldersAsync(IEnumerable<string> paths)
{
if (!JumpList.IsSupported())
return;
try
{
var pathsToRemove = paths.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (pathsToRemove.Count == 0)
return;
var instance = await JumpList.LoadCurrentAsync();
// Disable automatic jumplist. It doesn't work.
instance.SystemGroupKind = JumpListSystemGroupKind.None;
var itemsToRemove = instance.Items
.Where(item => pathsToRemove.Contains(item.Arguments))
.ToList();
foreach (var item in itemsToRemove)
instance.Items.Remove(item);
if (itemsToRemove.Count > 0)
await instance.SaveAsync();
}
catch (Exception ex)
{
App.Logger.LogWarning(ex, ex.Message);
}
}
private void AddFolder(string path, string group, JumpList instance)
{
if (instance is not null)
{
string? displayName = null;
if (path.StartsWith("\\\\SHELL", StringComparison.OrdinalIgnoreCase))
displayName = Strings.ThisPC.GetLocalizedResource();
if (path.EndsWith('\\'))
{
var drivesViewModel = Ioc.Default.GetRequiredService<DrivesViewModel>();
// 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 = drivesViewModel.Drives.FirstOrDefault(drive => drive.Id == path);
if (drive is null)
return;
displayName = (drive as DriveItem)?.Text;
path += '?';
}
if (displayName is null)
{
if (path.Equals(Constants.UserEnvironmentPaths.DesktopPath, StringComparison.OrdinalIgnoreCase))
displayName = "ms-resource:///Resources/Desktop";
else if (path.Equals(Constants.UserEnvironmentPaths.DownloadsPath, StringComparison.OrdinalIgnoreCase))
displayName = "ms-resource:///Resources/Downloads";
else if (path.Equals(Constants.UserEnvironmentPaths.NetworkFolderPath, StringComparison.OrdinalIgnoreCase))
displayName = Strings.Network.GetLocalizedResource();
else if (path.Equals(Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.OrdinalIgnoreCase))
displayName = Strings.RecycleBin.GetLocalizedResource();
else if (path.Equals(Constants.UserEnvironmentPaths.MyComputerPath, StringComparison.OrdinalIgnoreCase))
displayName = Strings.ThisPC.GetLocalizedResource();
else if (App.LibraryManager.TryGetLibrary(path, out LibraryLocationItem library))
{
var libName = Path.GetFileNameWithoutExtension(library.Path);
displayName = libName switch
{
"Documents" or "Pictures" or "Music" or "Videos" => $"ms-resource:///Resources/{libName}",// Use localized name
_ => library.Text,// Use original name
};
}
else
displayName = Path.GetFileName(path);
}
var jumplistItem = Windows.UI.StartScreen.JumpListItem.CreateWithArguments(path, displayName);
jumplistItem.Description = jumplistItem.Arguments ?? string.Empty;
jumplistItem.GroupName = group;
jumplistItem.Logo = new Uri("ms-appx:///Assets/FolderIcon.png");
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);
}
else
{
var pinnedItemsCount = instance.Items.Count(x => x.GroupName == JumpListPinnedGroupHeader);
instance.Items.Insert(pinnedItemsCount, jumplistItem);
}
}
}
private async void UpdateQuickAccessWidget_Invoked(object? sender, ModifyQuickAccessEventArgs e)
{
await RefreshPinnedFoldersAsync();
}
}
}