Skip to content
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
2 changes: 2 additions & 0 deletions src/Files.App/Data/Items/ListedItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public partial class ListedItem : ObservableObject, IGroupableItem, IListedItem

public byte[]? PreloadedIconData { get; set; }

public bool NeedsDelayedThumbnailLoad { get; set; }

private volatile int itemPropertiesInitialized = 0;
public bool ItemPropertiesInitialized
{
Expand Down
48 changes: 47 additions & 1 deletion src/Files.App/ViewModels/ShellViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public sealed partial class ShellViewModel : ObservableObject, IDisposable
private readonly SemaphoreSlim getFileOrFolderSemaphore;
private readonly SemaphoreSlim bulkOperationSemaphore;
private readonly SemaphoreSlim loadThumbnailSemaphore;
private readonly ConcurrentDictionary<string, CancellationTokenSource> thumbnailRetryDebounce;
private readonly ConcurrentQueue<(uint Action, string FileName)> operationQueue;
private readonly ConcurrentQueue<uint> gitChangesQueue;
private readonly ConcurrentDictionary<string, bool> itemLoadQueue;
Expand Down Expand Up @@ -561,6 +562,7 @@ public ShellViewModel(LayoutPreferencesManager folderSettingsViewModel)
operationQueue = new ConcurrentQueue<(uint Action, string FileName)>();
gitChangesQueue = new ConcurrentQueue<uint>();
itemLoadQueue = new ConcurrentDictionary<string, bool>();
thumbnailRetryDebounce = new ConcurrentDictionary<string, CancellationTokenSource>();
addFilesCTS = new CancellationTokenSource();
semaphoreCTS = new CancellationTokenSource();
loadPropsCTS = new CancellationTokenSource();
Expand Down Expand Up @@ -733,6 +735,12 @@ public void CancelLoadAndClearFiles()
addFilesCTS = new CancellationTokenSource();
}
CancelExtendedPropertiesLoading();
foreach (var cts in thumbnailRetryDebounce.Values)
{
cts.Cancel();
cts.Dispose();
}
thumbnailRetryDebounce.Clear();
filesAndFolders.Clear();
FilesAndFolders.Clear();
CancelSearch();
Expand Down Expand Up @@ -1170,7 +1178,11 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>

cancellationToken.ThrowIfCancellationRequested();

if (result is not null)
if (result is null)
{
item.NeedsDelayedThumbnailLoad = true;
}
else
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
Expand Down Expand Up @@ -2650,6 +2662,34 @@ private async Task AddFileOrFolderAsync(ListedItem? item)

private async Task UpdateFilesOrFoldersAsync(IEnumerable<string> paths, bool hasSyncStatus)
{
foreach (var path in paths)
{
var item = filesAndFolders.ToList().FirstOrDefault(x => x.ItemPath.Equals(path, StringComparison.OrdinalIgnoreCase));
if (item is not null && item.NeedsDelayedThumbnailLoad)
{
if (thumbnailRetryDebounce.TryGetValue(path, out var existingCts))
{
existingCts.Cancel();
existingCts.Dispose();
}

var debounceCts = new CancellationTokenSource();
thumbnailRetryDebounce[path] = debounceCts;
var debounceToken = debounceCts.Token;

_ = Task.Delay(500, debounceToken)
Comment thread
yair100 marked this conversation as resolved.
.ContinueWith(_ =>
{
if (thumbnailRetryDebounce.TryRemove(path, out var cts))
cts.Dispose();

item.NeedsDelayedThumbnailLoad = false;
return LoadThumbnailAsync(item, debounceToken);
}, debounceToken, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default)
.Unwrap();
}
}

try
{
await enumFolderSemaphore.WaitAsync(semaphoreCTS.Token);
Expand Down Expand Up @@ -2712,6 +2752,12 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
filesAndFolders.Remove(matchingItem);

if (thumbnailRetryDebounce.TryRemove(matchingItem.ItemPath, out var debounceCts))
{
debounceCts.Cancel();
debounceCts.Dispose();
}

if (UserSettingsService.FoldersSettingsService.AreAlternateStreamsVisible)
{
// Main file is removed, remove connected ADS
Expand Down
Loading