Skip to content

Commit 90831f1

Browse files
authored
Cache folder sizes at runtime (#7960)
1 parent db6ef1c commit 90831f1

File tree

8 files changed

+238
-106
lines changed

8 files changed

+238
-106
lines changed

src/Files/App.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ private IServiceProvider ConfigureServices()
111111

112112
// TODO: FileSystem operations:
113113
// (IFilesystemHelpersService, IFilesystemOperationsService)
114+
.AddSingleton<IFolderSizeProvider, FolderSizeProvider>()
114115

115116
; // End of service configuration
116117

src/Files/BaseLayout.cs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public abstract class BaseLayout : Page, IBaseLayout, INotifyPropertyChanged
4949

5050
protected IFileTagsSettingsService FileTagsSettingsService { get; } = Ioc.Default.GetService<IFileTagsSettingsService>();
5151

52+
protected IFolderSizeProvider FolderSizeProvider { get; } = Ioc.Default.GetService<IFolderSizeProvider>();
53+
5254
protected Task<NamedPipeAsAppServiceConnection> Connection => AppServiceConnectionHelper.Instance;
5355

5456
public SelectedItemsPropertiesViewModel SelectedItemsPropertiesViewModel { get; }
@@ -269,13 +271,7 @@ internal set
269271
{
270272
SelectedItemsPropertiesViewModel.SelectedItemsCountString = $"{SelectedItems.Count} {"ItemsSelected/Text".GetLocalized()}";
271273
ResetRenameDoubleClick();
272-
273-
bool isSizeKnown = !selectedItems.Any(item => string.IsNullOrEmpty(item.FileSize));
274-
if (isSizeKnown)
275-
{
276-
long size = selectedItems.Sum(item => item.FileSizeBytes);
277-
SelectedItemsPropertiesViewModel.ItemSize = size.ToSizeString();
278-
}
274+
UpdateSelectionSize();
279275
}
280276
}
281277

@@ -312,6 +308,8 @@ public BaseLayout()
312308

313309
dragOverTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
314310
tapDebounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
311+
312+
FolderSizeProvider.FolderSizeChanged += FolderSizeProvider_FolderSizeChanged;
315313
}
316314

317315
protected abstract void HookEvents();
@@ -531,6 +529,22 @@ private async void FolderSettings_GroupOptionPreferenceUpdated(object sender, Gr
531529
await ParentShellPageInstance.FilesystemViewModel.ReloadItemGroupHeaderImagesAsync();
532530
}
533531

532+
private void FolderSizeProvider_FolderSizeChanged(object sender, FolderSizeChangedEventArgs e)
533+
{
534+
if (e.Folder is null)
535+
{
536+
SelectedItemsPropertiesViewModel.ItemSizeBytes = 0;
537+
SelectedItemsPropertiesViewModel.ItemSize = string.Empty;
538+
SelectedItemsPropertiesViewModel.ItemSizeVisibility = false;
539+
}
540+
541+
var items = (selectedItems?.Any() ?? false) ? selectedItems : GetAllItems();
542+
if (items.Contains(e.Folder))
543+
{
544+
UpdateSelectionSize();
545+
}
546+
}
547+
534548
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
535549
{
536550
base.OnNavigatingFrom(e);
@@ -624,17 +638,28 @@ private void SelectedItem_PropertyChanged(object sender, PropertyChangedEventArg
624638
{
625639
if (e.PropertyName == nameof(ListedItem.FileSize))
626640
{
627-
var items = selectedItems;
628-
if (items is not null)
641+
UpdateSelectionSize();
642+
}
643+
}
644+
645+
private void UpdateSelectionSize()
646+
{
647+
var items = (selectedItems?.Any() ?? false) ? selectedItems : GetAllItems();
648+
if (items is not null)
649+
{
650+
bool isSizeKnown = !items.Any(item => string.IsNullOrEmpty(item.FileSize));
651+
if (isSizeKnown)
629652
{
630-
bool isSizeKnown = !items.Any(item => string.IsNullOrEmpty(item.FileSize));
631-
if (isSizeKnown)
632-
{
633-
long size = items.Sum(item => item.FileSizeBytes);
634-
SelectedItemsPropertiesViewModel.ItemSizeBytes = size;
635-
SelectedItemsPropertiesViewModel.ItemSize = size.ToSizeString();
636-
}
653+
long size = items.Sum(item => item.FileSizeBytes);
654+
SelectedItemsPropertiesViewModel.ItemSizeBytes = size;
655+
SelectedItemsPropertiesViewModel.ItemSize = size.ToSizeString();
656+
}
657+
else
658+
{
659+
SelectedItemsPropertiesViewModel.ItemSizeBytes = 0;
660+
SelectedItemsPropertiesViewModel.ItemSize = string.Empty;
637661
}
662+
SelectedItemsPropertiesViewModel.ItemSizeVisibility = isSizeKnown;
638663
}
639664
}
640665

src/Files/Files.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@
174174
<Compile Include="Extensions\KeyboardAcceleratorExtensions.cs" />
175175
<Compile Include="Filesystem\FilesystemOperations\ShellFilesystemOperations.cs" />
176176
<Compile Include="Filesystem\FileTagsHelper.cs" />
177+
<Compile Include="Filesystem\FolderSizeProvider.cs" />
177178
<Compile Include="Filesystem\FtpManager.cs" />
178179
<Compile Include="Filesystem\Permissions\FilePermissionsManager.cs" />
179180
<Compile Include="Filesystem\Permissions\FileSystemAccessRule.cs" />

src/Files/Filesystem/Drives.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace Files.Filesystem
2626
{
2727
public class DrivesManager : ObservableObject
2828
{
29+
private static readonly IFolderSizeProvider folderSizeProvider = Ioc.Default.GetService<IFolderSizeProvider>();
30+
2931
private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetService<IUserSettingsService>();
3032

3133
private static readonly Logger Logger = App.Logger;
@@ -103,6 +105,7 @@ private async void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, obje
103105
{
104106
System.Diagnostics.Debug.WriteLine("DeviceWatcher_EnumerationCompleted");
105107
await RefreshUI();
108+
folderSizeProvider.CleanCache();
106109
}
107110

108111
private async Task RefreshUI()

src/Files/Filesystem/FolderHelpers.cs

Lines changed: 8 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
using Files.Extensions;
2-
using Files.Filesystem.StorageItems;
1+
using Files.Filesystem.StorageItems;
32
using System;
43
using System.Collections.Generic;
54
using System.IO;
6-
using System.Threading;
75
using System.Threading.Tasks;
8-
using Windows.ApplicationModel.Core;
9-
using Windows.UI.Core;
106
using static Files.Helpers.NativeFindStorageItemHelper;
117

128
namespace Files.Filesystem
@@ -15,10 +11,8 @@ public static class FolderHelpers
1511
{
1612
public static bool CheckFolderAccessWithWin32(string path)
1713
{
18-
FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
19-
int additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
20-
IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero,
21-
additionalFlags);
14+
IntPtr hFileTsk = FindFirstFileExFromApp($"{path}{Path.DirectorySeparatorChar}*.*", FINDEX_INFO_LEVELS.FindExInfoBasic,
15+
out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FIND_FIRST_EX_LARGE_FETCH);
2216
if (hFileTsk.ToInt64() != -1)
2317
{
2418
FindClose(hFileTsk);
@@ -29,13 +23,14 @@ public static bool CheckFolderAccessWithWin32(string path)
2923

3024
public static async Task<bool> CheckBitlockerStatusAsync(BaseStorageFolder rootFolder, string path)
3125
{
32-
if (rootFolder == null || rootFolder.Properties == null)
26+
if (rootFolder?.Properties is null)
3327
{
3428
return false;
3529
}
3630
if (Path.IsPathRooted(path) && Path.GetPathRoot(path) == path)
3731
{
38-
IDictionary<string, object> extraProperties = await rootFolder.Properties.RetrievePropertiesAsync(new string[] { "System.Volume.BitLockerProtection" });
32+
IDictionary<string, object> extraProperties =
33+
await rootFolder.Properties.RetrievePropertiesAsync(new string[] { "System.Volume.BitLockerProtection" });
3934
return (int?)extraProperties["System.Volume.BitLockerProtection"] == 6; // Drive is bitlocker protected and locked
4035
}
4136
return false;
@@ -48,85 +43,12 @@ public static async Task<bool> CheckBitlockerStatusAsync(BaseStorageFolder rootF
4843
///
4944
public static bool CheckForFilesFolders(string targetPath)
5045
{
51-
FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
52-
int additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
53-
54-
IntPtr hFile = FindFirstFileExFromApp(targetPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags);
46+
IntPtr hFile = FindFirstFileExFromApp($"{targetPath}{Path.DirectorySeparatorChar}*.*", FINDEX_INFO_LEVELS.FindExInfoBasic,
47+
out WIN32_FIND_DATA _, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FIND_FIRST_EX_LARGE_FETCH);
5548
FindNextFile(hFile, out _);
5649
var result = FindNextFile(hFile, out _);
5750
FindClose(hFile);
5851
return result;
5952
}
60-
61-
public static async void UpdateFolder(ListedItem folder, CancellationToken cancellationToken)
62-
{
63-
CoreDispatcher dispatcher;
64-
65-
if (folder.PrimaryItemAttribute == Windows.Storage.StorageItemTypes.Folder && folder.FileSizeBytes == 0 && folder.ContainsFilesOrFolders)
66-
{
67-
dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
68-
69-
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
70-
{
71-
folder.FileSize = 0L.ToSizeString();
72-
});
73-
74-
_ = await Calculate(folder.ItemPath);
75-
}
76-
77-
async Task<long> Calculate(string folderPath)
78-
{
79-
if (string.IsNullOrEmpty(folderPath))
80-
{
81-
return 0;
82-
}
83-
84-
FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
85-
int additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
86-
87-
IntPtr hFile = FindFirstFileExFromApp(folderPath + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findData,
88-
FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags);
89-
90-
long size = 0;
91-
if (hFile.ToInt64() != -1)
92-
{
93-
do
94-
{
95-
if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
96-
{
97-
size += findData.GetSize();
98-
}
99-
else if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
100-
{
101-
if (findData.cFileName is not "." and not "..")
102-
{
103-
string path = Path.Combine(folderPath, findData.cFileName);
104-
size += await Calculate(path);
105-
}
106-
}
107-
108-
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
109-
{
110-
if (size > folder.FileSizeBytes)
111-
{
112-
folder.FileSizeBytes = size;
113-
folder.FileSize = size.ToSizeString();
114-
};
115-
});
116-
117-
if (cancellationToken.IsCancellationRequested)
118-
{
119-
break;
120-
}
121-
} while (FindNextFile(hFile, out findData));
122-
FindClose(hFile);
123-
return size;
124-
}
125-
else
126-
{
127-
return 0;
128-
}
129-
}
130-
}
13153
}
13254
}

0 commit comments

Comments
 (0)