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

Improve UI responsiveness while enumerating #5991

Merged
merged 2 commits into from
Sep 1, 2021
Merged
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
73 changes: 6 additions & 67 deletions Files/Filesystem/StorageEnumerators/UniversalStorageEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Files.Filesystem.StorageItems;
using Files.Helpers;
using Files.Views.LayoutModes;
using Microsoft.Toolkit.Uwp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -11,8 +12,6 @@
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.FileProperties;
using Windows.UI.Xaml.Media.Imaging;

namespace Files.Filesystem.StorageEnumerators
{
Expand Down Expand Up @@ -79,7 +78,7 @@ ex is UnauthorizedAccessException
}
else
{
var fileEntry = await AddFileAsync(item.AsBaseStorageFile(), currentStorageFolder, returnformat, true, sourcePageType, cancellationToken);
var fileEntry = await AddFileAsync(item.AsBaseStorageFile(), currentStorageFolder, returnformat, cancellationToken);
if (fileEntry != null)
{
tempList.Add(fileEntry);
Expand Down Expand Up @@ -168,8 +167,6 @@ private static async Task<ListedItem> AddFileAsync(
BaseStorageFile file,
StorageFolderWithPath currentStorageFolder,
string dateReturnFormat,
bool suppressThumbnailLoading,
Type sourcePageType,
CancellationToken cancellationToken
)
{
Expand All @@ -185,67 +182,9 @@ CancellationToken cancellationToken
var itemType = file.DisplayType;
var itemFolderImgVis = false;
var itemFileExtension = file.FileType;
var itemEmptyImgVis = true;
var itemThumbnailImgVis = false;

BitmapImage icon = new BitmapImage();
byte[] iconData = null;
bool itemThumbnailImgVis;
bool itemEmptyImgVis;

if (sourcePageType != typeof(GridViewBrowser))
{
try
{
using var itemThumbnailImg = suppressThumbnailLoading ? null :
await file.GetThumbnailAsync(ThumbnailMode.ListView, 40, ThumbnailOptions.UseCurrentScale);
if (itemThumbnailImg != null)
{
itemEmptyImgVis = false;
itemThumbnailImgVis = true;
icon.DecodePixelWidth = 40;
icon.DecodePixelHeight = 40;
await icon.SetSourceAsync(itemThumbnailImg);
iconData = await itemThumbnailImg.ToByteArrayAsync();
}
else
{
itemEmptyImgVis = true;
itemThumbnailImgVis = false;
}
}
catch
{
itemEmptyImgVis = true;
itemThumbnailImgVis = false;
// Catch here to avoid crash
}
}
else
{
try
{
using var itemThumbnailImg = suppressThumbnailLoading ? null :
await file.GetThumbnailAsync(ThumbnailMode.ListView, 80, ThumbnailOptions.UseCurrentScale);
if (itemThumbnailImg != null)
{
itemEmptyImgVis = false;
itemThumbnailImgVis = true;
icon.DecodePixelWidth = 80;
icon.DecodePixelHeight = 80;
await icon.SetSourceAsync(itemThumbnailImg);
iconData = await itemThumbnailImg.ToByteArrayAsync();
}
else
{
itemEmptyImgVis = true;
itemThumbnailImgVis = false;
}
}
catch
{
itemEmptyImgVis = true;
itemThumbnailImgVis = false;
}
}
if (cancellationToken.IsCancellationRequested)
{
return null;
Expand Down Expand Up @@ -274,8 +213,8 @@ CancellationToken cancellationToken
IsHiddenItem = false,
Opacity = 1,
LoadUnknownTypeGlyph = itemEmptyImgVis,
FileImage = icon,
CustomIconData = iconData,
FileImage = null,
CustomIconData = null,
LoadFileIcon = itemThumbnailImgVis,
LoadFolderGlyph = itemFolderImgVis,
ItemName = itemName,
Expand Down
73 changes: 40 additions & 33 deletions Files/ViewModels/ItemViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,19 +489,19 @@ public async Task ApplyFilesAndFoldersChangesAsync()
{
if (filesAndFolders == null || filesAndFolders.Count == 0)
{
Action action = () =>
void ClearDisplay()
{
FilesAndFolders.Clear();
UpdateEmptyTextType();
DirectoryInfoUpdated?.Invoke(this, EventArgs.Empty);
};
}
if (CoreApplication.MainView.DispatcherQueue.HasThreadAccess)
{
action();
ClearDisplay();
}
else
{
await CoreApplication.MainView.DispatcherQueue.EnqueueAsync(action);
await CoreApplication.MainView.DispatcherQueue.EnqueueAsync(ClearDisplay);
}
return;
}
Expand All @@ -517,7 +517,7 @@ public async Task ApplyFilesAndFoldersChangesAsync()
// After calling BeginBulkOperation, ObservableCollection.CollectionChanged is suppressed
// so modifies to FilesAndFolders won't trigger UI updates, hence below operations can be
// run safely without needs of dispatching to UI thread
Action applyChangesAction = () =>
void ApplyChanges()
{
var startIndex = -1;
var tempList = new List<ListedItem>();
Expand Down Expand Up @@ -572,26 +572,26 @@ void ApplyBulkInsertEntries()
{
OrderGroups();
}
};
}

Action updateUIAction = () =>
void UpdateUI()
{
// trigger CollectionChanged with NotifyCollectionChangedAction.Reset
// once loading is completed so that UI can be updated
FilesAndFolders.EndBulkOperation();
UpdateEmptyTextType();
DirectoryInfoUpdated?.Invoke(this, EventArgs.Empty);
};
}

if (CoreApplication.MainView.DispatcherQueue.HasThreadAccess)
{
await Task.Run(applyChangesAction);
updateUIAction();
await Task.Run(ApplyChanges);
UpdateUI();
}
else
{
applyChangesAction();
await CoreApplication.MainView.DispatcherQueue.EnqueueAsync(updateUIAction);
ApplyChanges();
await CoreApplication.MainView.DispatcherQueue.EnqueueAsync(UpdateUI);
}
}
catch (Exception ex)
Expand All @@ -608,23 +608,23 @@ private Task OrderFilesAndFoldersAsync()
return Task.CompletedTask;
}

Action action = () =>
void OrderEntries()
{
if (filesAndFolders.Count == 0)
{
return;
}

filesAndFolders = SortingHelper.OrderFileList(filesAndFolders, folderSettings.DirectorySortOption, folderSettings.DirectorySortDirection).ToList();
};
}

if (CoreApplication.MainView.DispatcherQueue.HasThreadAccess)
{
return Task.Run(action);
return Task.Run(OrderEntries);
}
else
{
action();
OrderEntries();
return Task.CompletedTask;
}
}
Expand Down Expand Up @@ -1584,16 +1584,20 @@ await DialogDisplayHelper.ShowDialogAsync(
}
else
{
List<ListedItem> fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, -1, intermediateAction: async (intermediateList) =>
await Task.Run(async () =>
{
filesAndFolders.AddRange(intermediateList);
List<ListedItem> fileList = await Win32StorageEnumerator.ListEntries(path, returnformat, hFile, findData, Connection, cancellationToken, -1, intermediateAction: async (intermediateList) =>
{
filesAndFolders.AddRange(intermediateList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
});

filesAndFolders.AddRange(fileList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
});

filesAndFolders.AddRange(fileList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
return 0;
}
}
Expand All @@ -1607,22 +1611,25 @@ private async Task EnumFromStorageFolderAsync(string path, ListedItem currentFol
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
string returnformat = Enum.Parse<TimeStyle>(localSettings.Values[Constants.LocalSettings.DateTimeFormat].ToString()) == TimeStyle.Application ? "D" : "g";

List<ListedItem> finalList = await UniversalStorageEnumerator.ListEntries(
rootFolder,
currentStorageFolder,
returnformat,
sourcePageType,
cancellationToken,
-1,
async (intermediateList) =>
await Task.Run(async () =>
{
filesAndFolders.AddRange(intermediateList);
List<ListedItem> finalList = await UniversalStorageEnumerator.ListEntries(
rootFolder,
currentStorageFolder,
returnformat,
sourcePageType,
cancellationToken,
-1,
async (intermediateList) =>
{
filesAndFolders.AddRange(intermediateList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
});
filesAndFolders.AddRange(finalList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
});
filesAndFolders.AddRange(finalList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();

stopwatch.Stop();
Debug.WriteLine($"Enumerating items in {path} (device) completed in {stopwatch.ElapsedMilliseconds} milliseconds.\n");
Expand Down