@@ -65,16 +65,17 @@ public async Task UpdateRecentFilesAsync()
65
65
List < RecentItem > enumeratedFiles = await ListRecentFilesAsync ( ) ;
66
66
if ( enumeratedFiles is not null )
67
67
{
68
+ var recentFilesSnapshot = RecentFiles ;
69
+
68
70
lock ( recentFiles )
69
71
{
70
72
recentFiles . Clear ( ) ;
71
73
recentFiles . AddRange ( enumeratedFiles ) ;
72
74
// do not sort here, enumeration order *is* the correct order since we get it from Quick Access
73
75
}
74
76
75
- // todo: potentially optimize this and figure out if list changed by either (1) Add (2) Remove (3) Move
76
- // this way the UI doesn't have to refresh the entire list everytime a change occurs
77
- RecentFilesChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Reset ) ) ;
77
+ var changedActionEventArgs = GetChangedActionEventArgs ( recentFilesSnapshot , enumeratedFiles ) ;
78
+ RecentFilesChanged ? . Invoke ( this , changedActionEventArgs ) ;
78
79
}
79
80
}
80
81
@@ -205,6 +206,55 @@ public Task<bool> UnpinFromRecentFiles(RecentItem item)
205
206
} ) ) ;
206
207
}
207
208
209
+ private NotifyCollectionChangedEventArgs GetChangedActionEventArgs ( IReadOnlyList < RecentItem > oldItems , IList < RecentItem > newItems )
210
+ {
211
+ // a single item was added
212
+ if ( newItems . Count == oldItems . Count + 1 )
213
+ {
214
+ var differences = newItems . Except ( oldItems ) ;
215
+ if ( differences . Take ( 2 ) . Count ( ) == 1 )
216
+ {
217
+ return new ( NotifyCollectionChangedAction . Add , newItems . First ( ) ) ;
218
+ }
219
+ }
220
+ // a single item was removed
221
+ else if ( newItems . Count == oldItems . Count - 1 )
222
+ {
223
+ var differences = oldItems . Except ( newItems ) ;
224
+ if ( differences . Take ( 2 ) . Count ( ) == 1 )
225
+ {
226
+ for ( int i = 0 ; i < oldItems . Count ; i ++ )
227
+ {
228
+ if ( i >= newItems . Count || ! newItems [ i ] . Equals ( oldItems [ i ] ) )
229
+ {
230
+ return new ( NotifyCollectionChangedAction . Remove , oldItems [ i ] , index : i ) ;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ // a single item was moved
236
+ else if ( newItems . Count == oldItems . Count )
237
+ {
238
+ var differences = oldItems . Except ( newItems ) ;
239
+ // desync due to skipped/batched calls, reset the list
240
+ if ( differences . Any ( ) )
241
+ {
242
+ return new ( NotifyCollectionChangedAction . Reset ) ;
243
+ }
244
+
245
+ // first diff from reversed is the designated item
246
+ for ( int i = oldItems . Count - 1 ; i >= 0 ; i -- )
247
+ {
248
+ if ( ! oldItems [ i ] . Equals ( newItems [ i ] ) )
249
+ {
250
+ return new ( NotifyCollectionChangedAction . Move , oldItems [ i ] , index : 0 , oldIndex : i ) ;
251
+ }
252
+ }
253
+ }
254
+
255
+ return new ( NotifyCollectionChangedAction . Reset ) ;
256
+ }
257
+
208
258
public bool CheckIsRecentFilesEnabled ( )
209
259
{
210
260
using var subkey = Registry . CurrentUser . OpenSubKey ( @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" ) ;
@@ -246,15 +296,6 @@ public bool CheckIsRecentFilesEnabled()
246
296
return true ;
247
297
}
248
298
249
- /// <summary>
250
- /// Returns whether two RecentItem enumerables have the same order.
251
- /// This function depends on `RecentItem` implementing IEquatable.
252
- /// </summary>
253
- private bool RecentItemsOrderEquals ( IEnumerable < RecentItem > oldOrder , IEnumerable < RecentItem > newOrder )
254
- {
255
- return oldOrder != null && newOrder != null && oldOrder . SequenceEqual ( newOrder ) ;
256
- }
257
-
258
299
public void Dispose ( )
259
300
{
260
301
RecentItemsManager . Default . RecentItemsChanged -= OnRecentItemsChanged ;
0 commit comments