diff --git a/src/Files.App/Helpers/Layout/LayoutPreferencesManager.cs b/src/Files.App/Helpers/Layout/LayoutPreferencesManager.cs index 8ae1cc18b1ee..89ebd24b7ebf 100644 --- a/src/Files.App/Helpers/Layout/LayoutPreferencesManager.cs +++ b/src/Files.App/Helpers/Layout/LayoutPreferencesManager.cs @@ -624,6 +624,8 @@ public static void SetLayoutPreferencesForPath(string? path, LayoutPreferencesIt if (string.IsNullOrEmpty(path)) return new(); +#if WINDOWS + // LINUX-TODO(listing): Uno's grouped CollectionView renders no rows, so Downloads is not grouped by default on Linux if (path == Constants.UserEnvironmentPaths.DownloadsPath) { // Default for downloads folder is to group by date created @@ -634,7 +636,9 @@ public static void SetLayoutPreferencesForPath(string? path, LayoutPreferencesIt DirectoryGroupByDateUnit = GroupByDateUnit.Year }; } - else if (LibraryManager.IsLibraryPath(path)) + else +#endif + if (LibraryManager.IsLibraryPath(path)) { // Default for libraries is to group by folder path return new() diff --git a/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs b/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs index 5357ef217b0d..96c3aa448e51 100644 --- a/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs +++ b/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs @@ -29,7 +29,7 @@ internal static class LinuxIconHelper private static IMimeTypeService Mime => Ioc.Default.GetRequiredService(); private static IUserDirectories Directories => Ioc.Default.GetRequiredService(); - public static async Task GetIconAsync(string? path, uint size, bool isFolder, IconOptions options) + public static async Task GetIconAsync(string? path, uint size, bool isFolder, IconOptions options, CancellationToken cancellationToken = default) { try { @@ -42,10 +42,9 @@ internal static class LinuxIconHelper if (!string.IsNullOrEmpty(path) && !isFolder && !options.HasFlag(IconOptions.ReturnIconOnly)) { - var thumbnail = await Thumbnails.GetThumbnailAsync( - path, - size, - options.HasFlag(IconOptions.ReturnOnlyIfCached) ? ThumbnailOptions.ReturnOnlyIfCached : ThumbnailOptions.None); + // The cache lookup reads files synchronously, and callers may be on the UI thread + var thumbnailOptions = options.HasFlag(IconOptions.ReturnOnlyIfCached) ? ThumbnailOptions.ReturnOnlyIfCached : ThumbnailOptions.None; + var thumbnail = await Task.Run(() => Thumbnails.GetThumbnailAsync(path, size, thumbnailOptions, cancellationToken), cancellationToken); if (thumbnail is not null) return thumbnail; diff --git a/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs b/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs index 398c5f4d1adf..556491a1a4a4 100644 --- a/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs +++ b/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs @@ -15,7 +15,7 @@ public static class FileThumbnailHelper /// /// Returns icon or thumbnail for given file or folder /// - public static async Task GetIconAsync(string? path, uint requestedSize, bool isFolder, IconOptions iconOptions) + public static async Task GetIconAsync(string? path, uint requestedSize, bool isFolder, IconOptions iconOptions, CancellationToken cancellationToken = default) { var scaledSize = requestedSize * App.AppModel.AppWindowDPI; @@ -26,7 +26,7 @@ public static class FileThumbnailHelper : _standardSizes.FirstOrDefault(s => s >= scaledSize, _standardSizes[^1]); #if !WINDOWS - return await LinuxIconHelper.GetIconAsync(path, size, isFolder, iconOptions); + return await LinuxIconHelper.GetIconAsync(path, size, isFolder, iconOptions, cancellationToken); #else if (!isFolder && !iconOptions.HasFlag(IconOptions.ReturnIconOnly) && !iconOptions.HasFlag(IconOptions.ReturnOnlyIfCached)) { diff --git a/src/Files.App/ViewModels/ShellViewModel.cs b/src/Files.App/ViewModels/ShellViewModel.cs index 0cc4af04d4ed..df9c96ac6255 100644 --- a/src/Files.App/ViewModels/ShellViewModel.cs +++ b/src/Files.App/ViewModels/ShellViewModel.cs @@ -1415,7 +1415,8 @@ private async Task LoadThumbnailAsync(ListedItem item, CancellationToken cancell item.ItemPath, thumbnailSize, item.IsFolder, - IconOptions.ReturnThumbnailOnly | IconOptions.ReturnOnlyIfCached); + IconOptions.ReturnThumbnailOnly | IconOptions.ReturnOnlyIfCached, + cancellationToken); cancellationToken.ThrowIfCancellationRequested(); loadNonCachedThumbnail = true; @@ -1433,7 +1434,8 @@ private async Task LoadThumbnailAsync(ListedItem item, CancellationToken cancell item.ItemPath, thumbnailSize, item.IsFolder, - IconOptions.ReturnIconOnly); + IconOptions.ReturnIconOnly, + cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } @@ -1457,7 +1459,8 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () => item.ItemPath, thumbnailSize, item.IsFolder, - (returnIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None)); + (returnIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None), + cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } @@ -2228,7 +2231,7 @@ private async Task RapidAddItemsToCollectionAsync(string? path, LibraryItem? lib public void CloseWatcher() { - App.Logger.LogInformation($"CloseWatcher: aProcessQueueAction={aProcessQueueAction?.Status.ToString()}, gitProcessQueueAction={gitProcessQueueAction?.Status.ToString()}"); + App.Logger.LogDebug($"CloseWatcher: aProcessQueueAction={aProcessQueueAction?.Status.ToString()}, gitProcessQueueAction={gitProcessQueueAction?.Status.ToString()}"); watcher?.Dispose(); watcher = null; diff --git a/src/Files.App/Views/Layouts/BaseLayoutPage.cs b/src/Files.App/Views/Layouts/BaseLayoutPage.cs index 96f7b4c68ef9..075db67fad24 100644 --- a/src/Files.App/Views/Layouts/BaseLayoutPage.cs +++ b/src/Files.App/Views/Layouts/BaseLayoutPage.cs @@ -1354,7 +1354,7 @@ private void LoadVisibleItemsAfterScrollSettled() } if (itemsToLoad.Count is not 0) - _ = Parallel.ForEachAsync(itemsToLoad, (item, _) => new ValueTask(LoadItemExtendedPropertiesAsync(item, shellViewModel))); + _ = Parallel.ForEachAsync(itemsToLoad, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (item, _) => new ValueTask(LoadItemExtendedPropertiesAsync(item, shellViewModel))); } private static async Task LoadItemExtendedPropertiesAsync(ListedItem item, ShellViewModel shellViewModel)