@@ -30,6 +30,7 @@ public sealed class ItemViewModel : ObservableObject, IDisposable
3030 private readonly SemaphoreSlim enumFolderSemaphore ;
3131 private readonly SemaphoreSlim getFileOrFolderSemaphore ;
3232 private readonly SemaphoreSlim bulkOperationSemaphore ;
33+ private readonly SemaphoreSlim loadThumbnailSemaphore ;
3334 private readonly ConcurrentQueue < ( uint Action , string FileName ) > operationQueue ;
3435 private readonly ConcurrentQueue < uint > gitChangesQueue ;
3536 private readonly ConcurrentDictionary < string , bool > itemLoadQueue ;
@@ -485,6 +486,7 @@ public ItemViewModel(LayoutPreferencesManager folderSettingsViewModel)
485486 enumFolderSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
486487 getFileOrFolderSemaphore = new SemaphoreSlim ( 50 ) ;
487488 bulkOperationSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
489+ loadThumbnailSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
488490 dispatcherQueue = DispatcherQueue . GetForCurrentThread ( ) ;
489491
490492 UserSettingsService . OnSettingChangedEvent += UserSettingsService_OnSettingChangedEvent ;
@@ -914,18 +916,51 @@ private async Task<BitmapImage> GetShieldIcon()
914916 return shieldIcon ;
915917 }
916918
917- private async Task LoadThumbnailAsync ( ListedItem item )
919+ private async Task LoadThumbnailAsync ( ListedItem item , CancellationToken cancellationToken )
918920 {
919- // Cancel if thumbnails aren't enabled
921+ var loadNonCachedThumbnail = false ;
920922 var thumbnailSize = folderSettings . GetRoundedIconSize ( ) ;
921923 var returnIconOnly = UserSettingsService . FoldersSettingsService . ShowThumbnails == false || thumbnailSize < 48 ;
922924
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+ }
929964
930965 if ( result is not null )
931966 {
@@ -936,17 +971,57 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
936971 if ( image is not null )
937972 item . FileImage = image ;
938973 } , Microsoft . UI . Dispatching . DispatcherQueuePriority . Low ) ;
974+
975+ cancellationToken . ThrowIfCancellationRequested ( ) ;
939976 }
940977
941978 // Get icon overlay
942979 var iconOverlay = await FileThumbnailHelper . GetIconOverlayAsync ( item . ItemPath , true ) ;
980+
981+ cancellationToken . ThrowIfCancellationRequested ( ) ;
982+
943983 if ( iconOverlay is not null )
944984 {
945985 await dispatcherQueue . EnqueueOrInvokeAsync ( async ( ) =>
946986 {
947987 item . IconOverlay = await iconOverlay . ToBitmapAsync ( ) ;
948988 item . ShieldIcon = await GetShieldIcon ( ) ;
949989 } , 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 ) ;
9501025 }
9511026 }
9521027
@@ -990,7 +1065,7 @@ public async Task LoadExtendedItemPropertiesAsync(ListedItem item)
9901065 }
9911066
9921067 cts . Token . ThrowIfCancellationRequested ( ) ;
993- await LoadThumbnailAsync ( item ) ;
1068+ await LoadThumbnailAsync ( item , cts . Token ) ;
9941069
9951070 cts . Token . ThrowIfCancellationRequested ( ) ;
9961071 if ( item . IsLibrary || item . PrimaryItemAttribute == StorageItemTypes . File || item . IsArchive )
@@ -1104,7 +1179,8 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
11041179 {
11051180 _ = Task . Run ( async ( ) => {
11061181 await Task . Delay ( 500 ) ;
1107- await LoadThumbnailAsync ( item ) ;
1182+ cts . Token . ThrowIfCancellationRequested ( ) ;
1183+ await LoadThumbnailAsync ( item , cts . Token ) ;
11081184 } ) ;
11091185 }
11101186 }
0 commit comments