Skip to content

Commit 8b837fb

Browse files
committed
WIP: Initial Improvements For Faster Item Loading
1 parent 24b7375 commit 8b837fb

File tree

2 files changed

+291
-1
lines changed

2 files changed

+291
-1
lines changed

Files/App.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public App()
9494
DetectCustomLocations();
9595
PopulatePinnedSidebarItems();
9696
DetectWSLDistros();
97-
QuickLookIntegration();
97+
//QuickLookIntegration(); <--- Prevent Crash
9898
LoadTerminalApps();
9999
}
100100

Files/Filesystem/ItemViewModel.cs

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System.Threading.Tasks;
1818
using Windows.ApplicationModel.Core;
1919
using Windows.Storage;
20+
using Windows.Storage.BulkAccess;
2021
using Windows.Storage.FileProperties;
2122
using Windows.Storage.Search;
2223
using Windows.UI.Core;
@@ -27,6 +28,7 @@
2728
using Windows.UI.Xaml.Data;
2829
using Windows.UI.Xaml.Media.Animation;
2930
using Windows.UI.Xaml.Media.Imaging;
31+
using FileAttributes = System.IO.FileAttributes;
3032

3133
namespace Files.Filesystem
3234
{
@@ -477,9 +479,297 @@ public static T GetCurrentSelectedTabInstance<T>()
477479
return default;
478480
}
479481

482+
public enum FINDEX_INFO_LEVELS
483+
{
484+
FindExInfoStandard = 0,
485+
FindExInfoBasic = 1
486+
}
487+
488+
public enum FINDEX_SEARCH_OPS
489+
{
490+
FindExSearchNameMatch = 0,
491+
FindExSearchLimitToDirectories = 1,
492+
FindExSearchLimitToDevices = 2
493+
}
494+
495+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
496+
public struct WIN32_FIND_DATA
497+
{
498+
public uint dwFileAttributes;
499+
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
500+
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
501+
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
502+
public uint nFileSizeHigh;
503+
public uint nFileSizeLow;
504+
public uint dwReserved0;
505+
public uint dwReserved1;
506+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
507+
public string cFileName;
508+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
509+
public string cAlternateFileName;
510+
}
511+
512+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
513+
public static extern IntPtr FindFirstFileExFromApp(
514+
string lpFileName,
515+
FINDEX_INFO_LEVELS fInfoLevelId,
516+
out WIN32_FIND_DATA lpFindFileData,
517+
FINDEX_SEARCH_OPS fSearchOp,
518+
IntPtr lpSearchFilter,
519+
int dwAdditionalFlags);
520+
521+
public const int FIND_FIRST_EX_CASE_SENSITIVE = 1;
522+
public const int FIND_FIRST_EX_LARGE_FETCH = 2;
523+
524+
[DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)]
525+
static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
526+
527+
[DllImport("api-ms-win-core-file-l1-1-0.dll")]
528+
static extern bool FindClose(IntPtr hFindFile);
529+
480530
bool isLoadingItems = false;
531+
532+
class PartialStorageItem
533+
{
534+
public string ItemName { get; set; }
535+
public string ContentType { get; set; }
536+
public StorageItemThumbnail Thumbnail { get; set; }
537+
public string RelativeId { get; set; }
538+
}
539+
540+
public async void RapidAddItemsToCollectionAsync(string path)
541+
{
542+
App.OccupiedInstance.RibbonArea.Refresh.IsEnabled = false;
543+
544+
Frame rootFrame = Window.Current.Content as Frame;
545+
var instanceTabsView = rootFrame.Content as InstanceTabsView;
546+
instanceTabsView.SetSelectedTabInfo(new DirectoryInfo(path).Name, path);
547+
CancelLoadAndClearFiles();
548+
549+
isLoadingItems = true;
550+
EmptyTextState.isVisible = Visibility.Collapsed;
551+
Universal.path = path;
552+
_filesAndFolders.Clear();
553+
Stopwatch stopwatch = new Stopwatch();
554+
stopwatch.Start();
555+
LoadIndicator.isVisible = Visibility.Visible;
556+
557+
switch (Universal.path)
558+
{
559+
case "Desktop":
560+
Universal.path = App.DesktopPath;
561+
break;
562+
case "Downloads":
563+
Universal.path = App.DownloadsPath;
564+
break;
565+
case "Documents":
566+
Universal.path = App.DocumentsPath;
567+
break;
568+
case "Pictures":
569+
Universal.path = App.PicturesPath;
570+
break;
571+
case "Music":
572+
Universal.path = App.MusicPath;
573+
break;
574+
case "Videos":
575+
Universal.path = App.VideosPath;
576+
break;
577+
case "OneDrive":
578+
Universal.path = App.OneDrivePath;
579+
break;
580+
}
581+
582+
_rootFolder = await StorageFolder.GetFolderFromPathAsync(path);
583+
QueryOptions options = new QueryOptions()
584+
{
585+
IndexerOption = IndexerOption.OnlyUseIndexerAndOptimizeForIndexedProperties,
586+
FolderDepth = FolderDepth.Shallow
587+
};
588+
var query = _rootFolder.CreateFileQueryWithOptions(options);
589+
options.SetPropertyPrefetch(PropertyPrefetchOptions.None, null);
590+
options.SetThumbnailPrefetch(ThumbnailMode.ListView, 40, ThumbnailOptions.ReturnOnlyIfCached);
591+
FileInformationFactory thumbnailFactory = new FileInformationFactory(query, ThumbnailMode.ListView, 40, ThumbnailOptions.ReturnOnlyIfCached, false);
592+
593+
var singlePurposedFiles = await thumbnailFactory.GetFilesAsync();
594+
ObservableCollection<PartialStorageItem> partialFiles = new System.Collections.ObjectModel.ObservableCollection<PartialStorageItem>();
595+
foreach(FileInformation info in singlePurposedFiles)
596+
{
597+
partialFiles.Add(new PartialStorageItem() { RelativeId = info.FolderRelativeId, Thumbnail = info.Thumbnail, ItemName = info.Name, ContentType = info.DisplayType });
598+
}
599+
600+
var singlePurposedFolders = await thumbnailFactory.GetFoldersAsync();
601+
ObservableCollection<PartialStorageItem> partialFolders = new System.Collections.ObjectModel.ObservableCollection<PartialStorageItem>();
602+
foreach(FolderInformation info in singlePurposedFolders)
603+
{
604+
partialFolders.Add(new PartialStorageItem() { RelativeId = info.FolderRelativeId, ItemName = info.Name, ContentType = null, Thumbnail = null });
605+
}
606+
607+
WIN32_FIND_DATA findData;
608+
FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoStandard;
609+
int additionalFlags = 0;
610+
findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
611+
additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
612+
613+
IntPtr hFile = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out findData, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero,
614+
additionalFlags);
615+
var count = 0;
616+
if (hFile.ToInt64() != -1)
617+
{
618+
do
619+
{
620+
if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
621+
{
622+
AddFile(findData, path, partialFiles.FirstOrDefault(x => x.ItemName == findData.cFileName));
623+
++count;
624+
}
625+
else if(((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
626+
{
627+
AddFolder(findData, path, partialFolders.FirstOrDefault(x => x.ItemName == findData.cFileName));
628+
++count;
629+
}
630+
} while (FindNextFile(hFile, out findData));
631+
632+
FindClose(hFile);
633+
}
634+
635+
636+
if (FilesAndFolders.Count == 0)
637+
{
638+
if (_cancellationTokenSource.IsCancellationRequested)
639+
{
640+
_cancellationTokenSource = new CancellationTokenSource();
641+
isLoadingItems = false;
642+
return;
643+
}
644+
EmptyTextState.isVisible = Visibility.Visible;
645+
}
646+
647+
648+
OrderFiles();
649+
stopwatch.Stop();
650+
Debug.WriteLine("Loading of items in " + Universal.path + " completed in " + stopwatch.ElapsedMilliseconds + " milliseconds.\n");
651+
App.OccupiedInstance.RibbonArea.Refresh.IsEnabled = true;
652+
LoadIndicator.isVisible = Visibility.Collapsed;
653+
isLoadingItems = false;
654+
}
655+
656+
private void AddFolder(WIN32_FIND_DATA findData, string pathRoot, PartialStorageItem partialStorageItem)
657+
{
658+
if ((App.OccupiedInstance.ItemDisplayFrame.SourcePageType == typeof(GenericFileBrowser)) || (App.OccupiedInstance.ItemDisplayFrame.SourcePageType == typeof(PhotoAlbum)))
659+
{
660+
if (_cancellationTokenSource.IsCancellationRequested)
661+
{
662+
isLoadingItems = false;
663+
return;
664+
}
665+
var itemDate = DateTime.FromFileTimeUtc((findData.ftLastWriteTime.dwHighDateTime << 32) + (long)(uint)findData.ftLastWriteTime.dwLowDateTime);
666+
var itemPath = Path.Combine(pathRoot, findData.cFileName);
667+
668+
_filesAndFolders.Add(new ListedItem(partialStorageItem?.RelativeId)
669+
{
670+
//FolderTooltipText = tooltipString,
671+
FileName = findData.cFileName,
672+
FileDateReal = itemDate,
673+
FileType = "Folder", //TODO: Take a look at folder.DisplayType
674+
FolderImg = Visibility.Visible,
675+
FileImg = null,
676+
FileIconVis = Visibility.Collapsed,
677+
FilePath = itemPath,
678+
EmptyImgVis = Visibility.Collapsed,
679+
FileSize = null,
680+
FileSizeBytes = 0
681+
});
682+
683+
EmptyTextState.isVisible = Visibility.Collapsed;
684+
}
685+
}
686+
687+
private async void AddFile(WIN32_FIND_DATA findData, string pathRoot, PartialStorageItem partialStorageFile)
688+
{
689+
690+
var itemName = findData.cFileName;
691+
var itemDate = DateTime.FromFileTimeUtc((findData.ftLastWriteTime.dwHighDateTime << 32) + (long) (uint) findData.ftLastWriteTime.dwLowDateTime);
692+
var itemPath = Path.Combine(pathRoot, findData.cFileName);
693+
var itemSize = ByteSize.FromBytes((findData.nFileSizeHigh << 32) + (long)(uint)findData.nFileSizeLow).ToString();
694+
var itemSizeBytes = (findData.nFileSizeHigh << 32) + (ulong)(uint)findData.nFileSizeLow;
695+
string itemType = "File";
696+
if(partialStorageFile != null)
697+
{
698+
itemType = partialStorageFile.ContentType;
699+
}
700+
else
701+
{
702+
if (findData.cFileName.Contains('.'))
703+
{
704+
itemType = findData.cFileName.Split('.')[1].ToUpper() + " File";
705+
}
706+
}
707+
708+
var itemFolderImgVis = Visibility.Collapsed;
709+
string itemFileExtension = null;
710+
if (findData.cFileName.Contains('.'))
711+
{
712+
itemFileExtension = findData.cFileName.Split('.')[1];
713+
}
714+
715+
BitmapImage icon = new BitmapImage();
716+
Visibility itemThumbnailImgVis;
717+
Visibility itemEmptyImgVis;
718+
719+
try
720+
{
721+
722+
var itemThumbnailImg = partialStorageFile != null ? partialStorageFile.Thumbnail.CloneStream() : null;
723+
if (itemThumbnailImg != null)
724+
{
725+
itemEmptyImgVis = Visibility.Collapsed;
726+
itemThumbnailImgVis = Visibility.Visible;
727+
icon.DecodePixelWidth = 40;
728+
icon.DecodePixelHeight = 40;
729+
await icon.SetSourceAsync(itemThumbnailImg);
730+
}
731+
else
732+
{
733+
itemEmptyImgVis = Visibility.Visible;
734+
itemThumbnailImgVis = Visibility.Collapsed;
735+
}
736+
}
737+
catch
738+
{
739+
itemEmptyImgVis = Visibility.Visible;
740+
itemThumbnailImgVis = Visibility.Collapsed;
741+
// Catch here to avoid crash
742+
// TODO maybe some logging could be added in the future...
743+
}
744+
745+
if (_cancellationTokenSource.IsCancellationRequested)
746+
{
747+
isLoadingItems = false;
748+
return;
749+
}
750+
_filesAndFolders.Add(new ListedItem(partialStorageFile?.RelativeId)
751+
{
752+
DotFileExtension = itemFileExtension,
753+
EmptyImgVis = itemEmptyImgVis,
754+
FileImg = icon,
755+
FileIconVis = itemThumbnailImgVis,
756+
FolderImg = itemFolderImgVis,
757+
FileName = itemName,
758+
FileDateReal = itemDate,
759+
FileType = itemType,
760+
FilePath = itemPath,
761+
FileSize = itemSize,
762+
FileSizeBytes = itemSizeBytes
763+
});
764+
765+
EmptyTextState.isVisible = Visibility.Collapsed;
766+
}
767+
481768
public async void AddItemsToCollectionAsync(string path)
482769
{
770+
RapidAddItemsToCollectionAsync(path);
771+
return;
772+
483773
App.OccupiedInstance.RibbonArea.Refresh.IsEnabled = false;
484774

485775
Frame rootFrame = Window.Current.Content as Frame;

0 commit comments

Comments
 (0)