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

Code Quality: Remove thumbnail cache to simplify logic and improve performance #14871

Merged
merged 12 commits into from
Mar 3, 2024
167 changes: 37 additions & 130 deletions src/Files.App/Data/Models/ItemViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -900,29 +900,6 @@ public void UpdateGroupOptions()
FilesAndFolders.GetExtendedGroupHeaderInfo = groupInfoSelector.Item2;
}

public Dictionary<string, BitmapImage> DefaultIcons = new();

private uint currentDefaultIconSize = 0;

public async Task GetDefaultItemIconsAsync(uint size)
{
if (currentDefaultIconSize == size)
return;

DefaultIcons.Clear();

// TODO: Add more than just the folder icon
using StorageItemThumbnail icon = await FilesystemTasks.Wrap(() => StorageItemIconHelpers.GetIconForItemType(size, IconPersistenceOptions.Persist));
if (icon is not null)
{
var img = new BitmapImage();
await img.SetSourceAsync(icon);
DefaultIcons.Add(string.Empty, img);
}

currentDefaultIconSize = size;
}

private bool isLoadingItems = false;
public bool IsLoadingItems
{
Expand All @@ -937,117 +914,40 @@ private async Task<BitmapImage> GetShieldIcon()
return shieldIcon;
}

private async Task LoadItemThumbnailAsync(ListedItem item)
private async Task LoadThumbnailAsync(ListedItem item)
{
// Cancel if thumbnails aren't enabled
var thumbnailSize = folderSettings.GetRoundedIconSize();
var returnIconOnly = UserSettingsService.FoldersSettingsService.ShowThumbnails == false || thumbnailSize < 48;

if (item.IsLibrary || item.PrimaryItemAttribute == StorageItemTypes.File || item.IsArchive)
{
var getIconOnly = UserSettingsService.FoldersSettingsService.ShowThumbnails == false || thumbnailSize < 48;
var getThumbnailOnly = !item.IsExecutable && !getIconOnly;
var iconInfo = await FileThumbnailHelper.GetIconAsync(
// Get thumbnail
var icon = await FileThumbnailHelper.GetIconAsync(
item.ItemPath,
thumbnailSize,
item.IsFolder,
false,
getThumbnailOnly,
getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (!iconInfo.isIconCached)
{
// Assign a placeholder icon while trying to get a cached thumbnail
if (iconInfo.IconData is not null)
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.FileImage = await iconInfo.IconData.ToBitmapAsync();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}

// Loop until cached thumbnail is loaded or timeout is reached
var cancellationTokenSource = new CancellationTokenSource(3000);
while (!iconInfo.isIconCached)
{
iconInfo = await FileThumbnailHelper.GetIconAsync(
item.ItemPath,
thumbnailSize,
false,
getThumbnailOnly,
getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (cancellationTokenSource.Token.IsCancellationRequested)
break;

await Task.Delay(500);
}
}
returnIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (iconInfo.IconData is not null)
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
// Assign the thumbnail/icon to the listed item
item.FileImage = await iconInfo.IconData.ToBitmapAsync();

// Add the file icon to the DefaultIcons list
if
(
!DefaultIcons.ContainsKey(item.FileExtension.ToLowerInvariant()) &&
!string.IsNullOrEmpty(item.FileExtension) &&
!item.IsShortcut &&
!item.IsExecutable
)
{
var fileIcon = await FileThumbnailHelper.GetIconAsync(
item.ItemPath,
thumbnailSize,
false,
false,
IconOptions.ReturnIconOnly);

var bitmapImage = await fileIcon.IconData.ToBitmapAsync();
DefaultIcons.TryAdd(item.FileExtension.ToLowerInvariant(), bitmapImage);
}

}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}

var iconOverlay = await FileThumbnailHelper.GetIconOverlayAsync(item.ItemPath, false);
if (iconOverlay is not null)
{
// Assign the icon overlay to the listed item
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.IconOverlay = await iconOverlay.ToBitmapAsync();
item.ShieldIcon = await GetShieldIcon();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
}
else
if (icon.IconData is not null)
{
var getIconOnly = UserSettingsService.FoldersSettingsService.ShowThumbnails == false || thumbnailSize < 48;
var iconInfo = await FileThumbnailHelper.GetIconAsync(
item.ItemPath,
thumbnailSize,
true,
false, getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (iconInfo.IconData is not null)
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.FileImage = await iconInfo.IconData.ToBitmapAsync();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
// Assign FileImage property
var image = await icon.IconData.ToBitmapAsync();
if (image is not null)
item.FileImage = image;
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}

var iconOverlay = await FileThumbnailHelper.GetIconOverlayAsync(item.ItemPath, true);
if (iconOverlay is not null)
// Get icon overlay
var iconOverlay = await FileThumbnailHelper.GetIconOverlayAsync(item.ItemPath, true);
if (iconOverlay is not null)
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.IconOverlay = await iconOverlay.ToBitmapAsync();
item.ShieldIcon = await GetShieldIcon();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
item.IconOverlay = await iconOverlay.ToBitmapAsync();
item.ShieldIcon = await GetShieldIcon();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
}

Expand Down Expand Up @@ -1092,7 +992,7 @@ await Task.Run(async () =>
}

cts.Token.ThrowIfCancellationRequested();
_ = LoadItemThumbnailAsync(item);
_ = LoadThumbnailAsync(item);

if (item.IsLibrary || item.PrimaryItemAttribute == StorageItemTypes.File || item.IsArchive)
{
Expand Down Expand Up @@ -1198,6 +1098,17 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
SetFileTag(item);
});
}
else
{
// Try loading thumbnail for cloud files in case they weren't cached the first time
if (item.SyncStatusUI.SyncStatus != CloudDriveSyncStatus.NotSynced && item.SyncStatusUI.SyncStatus != CloudDriveSyncStatus.Unknown)
{
_ = Task.Run(async () => {
await Task.Delay(500);
await LoadThumbnailAsync(item);
});
}
}

if (loadGroupHeaderInfo)
{
Expand Down Expand Up @@ -1473,8 +1384,6 @@ private async Task RapidAddItemsToCollectionAsync(string? path, LibraryItem? lib
break;
}

await GetDefaultItemIconsAsync(folderSettings.GetRoundedIconSize());

if (IsLoadingCancelled)
{
IsLoadingCancelled = false;
Expand Down Expand Up @@ -1693,7 +1602,7 @@ await Task.Run(async () =>
filesAndFolders.AddRange(intermediateList);
await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
}, defaultIconPairs: DefaultIcons);
});

filesAndFolders.AddRange(fileList);

Expand Down Expand Up @@ -1741,8 +1650,7 @@ await Task.Run(async () =>

await OrderFilesAndFoldersAsync();
await ApplyFilesAndFoldersChangesAsync();
},
defaultIconPairs: DefaultIcons);
});

filesAndFolders.AddRange(finalList);

Expand Down Expand Up @@ -2481,7 +2389,6 @@ public void Dispose()
fileTagsSettingsService.OnSettingImportedEvent -= FileTagsSettingsService_OnSettingUpdated;
fileTagsSettingsService.OnTagsUpdated -= FileTagsSettingsService_OnSettingUpdated;
folderSizeProvider.SizeChanged -= FolderSizeProvider_SizeChanged;
DefaultIcons.Clear();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ public static async Task<List<ListedItem>> ListEntries(
NativeFindStorageItemHelper.WIN32_FIND_DATA findData,
CancellationToken cancellationToken,
int countLimit,
Func<List<ListedItem>, Task> intermediateAction,
Dictionary<string, BitmapImage> defaultIconPairs = null
Func<List<ListedItem>, Task> intermediateAction
)
{
var sampler = new IntervalSampler(500);
Expand All @@ -54,18 +53,6 @@ public static async Task<List<ListedItem>> ListEntries(
var file = await GetFile(findData, path, isGitRepo, cancellationToken);
if (file is not null)
{
if (defaultIconPairs is not null)
{
if (!string.IsNullOrEmpty(file.FileExtension))
{
var lowercaseExtension = file.FileExtension.ToLowerInvariant();
if (defaultIconPairs.ContainsKey(lowercaseExtension))
{
file.FileImage = defaultIconPairs[lowercaseExtension];
}
}
}

tempList.Add(file);
++count;

Expand All @@ -82,12 +69,6 @@ public static async Task<List<ListedItem>> ListEntries(
var folder = await GetFolder(findData, path, isGitRepo, cancellationToken);
if (folder is not null)
{
if (defaultIconPairs?.ContainsKey(string.Empty) ?? false)
{
// Set folder icon (found by empty extension string)
folder.FileImage = defaultIconPairs[string.Empty];
}

tempList.Add(folder);
++count;

Expand Down
Loading