@@ -30,6 +30,7 @@ public sealed class ItemViewModel : ObservableObject, IDisposable
30
30
private readonly SemaphoreSlim enumFolderSemaphore ;
31
31
private readonly SemaphoreSlim getFileOrFolderSemaphore ;
32
32
private readonly SemaphoreSlim bulkOperationSemaphore ;
33
+ private readonly SemaphoreSlim loadThumbnailSemaphore ;
33
34
private readonly ConcurrentQueue < ( uint Action , string FileName ) > operationQueue ;
34
35
private readonly ConcurrentQueue < uint > gitChangesQueue ;
35
36
private readonly ConcurrentDictionary < string , bool > itemLoadQueue ;
@@ -485,6 +486,7 @@ public ItemViewModel(LayoutPreferencesManager folderSettingsViewModel)
485
486
enumFolderSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
486
487
getFileOrFolderSemaphore = new SemaphoreSlim ( 50 ) ;
487
488
bulkOperationSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
489
+ loadThumbnailSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
488
490
dispatcherQueue = DispatcherQueue . GetForCurrentThread ( ) ;
489
491
490
492
UserSettingsService . OnSettingChangedEvent += UserSettingsService_OnSettingChangedEvent ;
@@ -914,18 +916,51 @@ private async Task<BitmapImage> GetShieldIcon()
914
916
return shieldIcon ;
915
917
}
916
918
917
- private async Task LoadThumbnailAsync ( ListedItem item )
919
+ private async Task LoadThumbnailAsync ( ListedItem item , CancellationToken cancellationToken )
918
920
{
919
- // Cancel if thumbnails aren't enabled
921
+ var loadNonCachedThumbnail = false ;
920
922
var thumbnailSize = folderSettings . GetRoundedIconSize ( ) ;
921
923
var returnIconOnly = UserSettingsService . FoldersSettingsService . ShowThumbnails == false || thumbnailSize < 48 ;
922
924
923
- // Get thumbnail
924
- var result = await FileThumbnailHelper . GetIconAsync (
925
- item . ItemPath ,
926
- thumbnailSize ,
927
- item . IsFolder ,
928
- returnIconOnly ? IconOptions . ReturnIconOnly : IconOptions . None ) ;
925
+ byte [ ] ? result = null ;
926
+ if ( item . IsFolder )
927
+ {
928
+ if ( ! returnIconOnly )
929
+ {
930
+ // Get cached thumbnail
931
+ result = await FileThumbnailHelper . GetIconAsync (
932
+ item . ItemPath ,
933
+ thumbnailSize ,
934
+ item . IsFolder ,
935
+ IconOptions . ReturnThumbnailOnly | IconOptions . ReturnOnlyIfCached ) ;
936
+
937
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
938
+ loadNonCachedThumbnail = true ;
939
+ }
940
+
941
+ if ( result is null )
942
+ {
943
+ // Get icon
944
+ result = await FileThumbnailHelper . GetIconAsync (
945
+ item . ItemPath ,
946
+ thumbnailSize ,
947
+ item . IsFolder ,
948
+ IconOptions . ReturnIconOnly ) ;
949
+
950
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
951
+ }
952
+ }
953
+ else
954
+ {
955
+ // Get icon or thumbnail
956
+ result = await FileThumbnailHelper . GetIconAsync (
957
+ item . ItemPath ,
958
+ thumbnailSize ,
959
+ item . IsFolder ,
960
+ returnIconOnly ? IconOptions . ReturnIconOnly : IconOptions . None ) ;
961
+
962
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
963
+ }
929
964
930
965
if ( result is not null )
931
966
{
@@ -936,17 +971,57 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
936
971
if ( image is not null )
937
972
item . FileImage = image ;
938
973
} , Microsoft . UI . Dispatching . DispatcherQueuePriority . Low ) ;
974
+
975
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
939
976
}
940
977
941
978
// Get icon overlay
942
979
var iconOverlay = await FileThumbnailHelper . GetIconOverlayAsync ( item . ItemPath , true ) ;
980
+
981
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
982
+
943
983
if ( iconOverlay is not null )
944
984
{
945
985
await dispatcherQueue . EnqueueOrInvokeAsync ( async ( ) =>
946
986
{
947
987
item . IconOverlay = await iconOverlay . ToBitmapAsync ( ) ;
948
988
item . ShieldIcon = await GetShieldIcon ( ) ;
949
989
} , Microsoft . UI . Dispatching . DispatcherQueuePriority . Low ) ;
990
+
991
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
992
+ }
993
+
994
+ if ( loadNonCachedThumbnail )
995
+ {
996
+ // Get non-cached thumbnail asynchronously
997
+ _ = Task . Run ( async ( ) => {
998
+ await loadThumbnailSemaphore . WaitAsync ( cancellationToken ) ;
999
+ try
1000
+ {
1001
+ result = await FileThumbnailHelper . GetIconAsync (
1002
+ item . ItemPath ,
1003
+ thumbnailSize ,
1004
+ item . IsFolder ,
1005
+ IconOptions . ReturnThumbnailOnly ) ;
1006
+ }
1007
+ finally
1008
+ {
1009
+ loadThumbnailSemaphore . Release ( ) ;
1010
+ }
1011
+
1012
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
1013
+
1014
+ if ( result is not null )
1015
+ {
1016
+ await dispatcherQueue . EnqueueOrInvokeAsync ( async ( ) =>
1017
+ {
1018
+ // Assign FileImage property
1019
+ var image = await result . ToBitmapAsync ( ) ;
1020
+ if ( image is not null )
1021
+ item . FileImage = image ;
1022
+ } , Microsoft . UI . Dispatching . DispatcherQueuePriority . Low ) ;
1023
+ }
1024
+ } , cancellationToken ) ;
950
1025
}
951
1026
}
952
1027
@@ -990,7 +1065,7 @@ public async Task LoadExtendedItemPropertiesAsync(ListedItem item)
990
1065
}
991
1066
992
1067
cts . Token . ThrowIfCancellationRequested ( ) ;
993
- await LoadThumbnailAsync ( item ) ;
1068
+ await LoadThumbnailAsync ( item , cts . Token ) ;
994
1069
995
1070
cts . Token . ThrowIfCancellationRequested ( ) ;
996
1071
if ( item . IsLibrary || item . PrimaryItemAttribute == StorageItemTypes . File || item . IsArchive )
@@ -1104,7 +1179,8 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
1104
1179
{
1105
1180
_ = Task . Run ( async ( ) => {
1106
1181
await Task . Delay ( 500 ) ;
1107
- await LoadThumbnailAsync ( item ) ;
1182
+ cts . Token . ThrowIfCancellationRequested ( ) ;
1183
+ await LoadThumbnailAsync ( item , cts . Token ) ;
1108
1184
} ) ;
1109
1185
}
1110
1186
}
0 commit comments