From 29c3b256271eafeb01cb3006010369c8feaaee88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20B=C3=A1lint=20Hunor?= Date: Mon, 5 Oct 2026 22:11:54 +0300 Subject: [PATCH] Isolate remaining Windows-only code (P4 orphans) Move RemovableDevice, SyncRootHelpers (with a Linux stub) and the Win32 breadcrumb subfolder enumeration into *.Windows.cs files. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01LeKXJc3DnK3PzAqwgA72NY --- ...leDevice.cs => RemovableDevice.Windows.cs} | 0 src/Files.App/Files.App.csproj | 1 + .../Storage/Helpers/SyncRootHelpers.Linux.cs | 12 ++++ ...tHelpers.cs => SyncRootHelpers.Windows.cs} | 0 .../NavigationToolbarViewModel.Windows.cs | 63 +++++++++++++++++++ .../NavigationToolbarViewModel.cs | 56 ++--------------- 6 files changed, 80 insertions(+), 52 deletions(-) rename src/Files.App/Data/Models/{RemovableDevice.cs => RemovableDevice.Windows.cs} (100%) create mode 100644 src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Linux.cs rename src/Files.App/Utils/Storage/Helpers/{SyncRootHelpers.cs => SyncRootHelpers.Windows.cs} (100%) create mode 100644 src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.Windows.cs diff --git a/src/Files.App/Data/Models/RemovableDevice.cs b/src/Files.App/Data/Models/RemovableDevice.Windows.cs similarity index 100% rename from src/Files.App/Data/Models/RemovableDevice.cs rename to src/Files.App/Data/Models/RemovableDevice.Windows.cs diff --git a/src/Files.App/Files.App.csproj b/src/Files.App/Files.App.csproj index c4584b8d98c4..82dd3eb7800d 100644 --- a/src/Files.App/Files.App.csproj +++ b/src/Files.App/Files.App.csproj @@ -245,6 +245,7 @@ + diff --git a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Linux.cs b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Linux.cs new file mode 100644 index 000000000000..c1278b42223e --- /dev/null +++ b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Linux.cs @@ -0,0 +1,12 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +namespace Files.App.Utils.Storage +{ + internal static class SyncRootHelpers + { + // LINUX-TODO(cloud): Windows cloud sync roots have no Linux equivalent; report no quota. + public static Task<(bool Success, ulong Capacity, ulong Used)> GetSyncRootQuotaAsync(string path) + => Task.FromResult((false, 0ul, 0ul)); + } +} diff --git a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Windows.cs similarity index 100% rename from src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs rename to src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.Windows.cs diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.Windows.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.Windows.cs new file mode 100644 index 000000000000..7e6304367e39 --- /dev/null +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.Windows.cs @@ -0,0 +1,63 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using Files.Shared.Helpers; +using System.IO; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; + +namespace Files.App.ViewModels.UserControls +{ + public sealed partial class NavigationToolbarViewModel + { + /// + /// Enumerates subfolders using Win32 API, including hidden folders based on user settings. + /// Returns null if the path cannot be enumerated with Win32. + /// + private unsafe List<(string Name, string Path, bool IsHidden)>? GetSubfolders(string parentPath) + { + WIN32_FIND_DATAW findData = default; + using FindCloseSafeHandle hFile = PInvoke.FindFirstFileEx( + $"{parentPath}{Path.DirectorySeparatorChar}*.*", + FINDEX_INFO_LEVELS.FindExInfoBasic, + &findData, + FINDEX_SEARCH_OPS.FindExSearchNameMatch, + FIND_FIRST_EX_FLAGS.FIND_FIRST_EX_LARGE_FETCH); + + if (hFile.IsInvalid) + return null; + + var showHidden = UserSettingsService.FoldersSettingsService.ShowHiddenItems; + var showSystem = UserSettingsService.FoldersSettingsService.ShowProtectedSystemFiles; + var showDot = UserSettingsService.FoldersSettingsService.ShowDotFiles; + var folders = new List<(string Name, string Path, bool IsHidden)>(); + + do + { + if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == 0) + continue; + + string fileName = findData.cFileName.ToString(); + if (fileName is "." or "..") + continue; + + bool isHidden = ((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) != 0; + bool isSystem = ((FileAttributes)findData.dwFileAttributes & FileAttributes.System) != 0; + + if (isHidden && (!showHidden || (isSystem && !showSystem))) + continue; + + if (fileName.StartsWith('.') && !showDot) + continue; + + folders.Add((fileName, Path.Combine(parentPath, fileName), isHidden)); + } + while (PInvoke.FindNextFile(hFile, out findData)); + + var naturalComparer = NaturalStringComparer.GetForProcessor(); + folders.Sort((a, b) => naturalComparer.Compare(a.Name, b.Name)); + + return folders; + } + } +} diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs index 0117efa57cbc..03ca6d89c6b0 100644 --- a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs @@ -14,8 +14,6 @@ using System.Windows.Input; using Windows.ApplicationModel.DataTransfer; using WinRT; -using Windows.Win32; -using Windows.Win32.Storage.FileSystem; namespace Files.App.ViewModels.UserControls { @@ -712,7 +710,11 @@ public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem p var path = pathItem.Path ?? throw new InvalidOperationException("The path box item does not have a path."); +#if WINDOWS var childFolders = OperatingSystem.IsWindows() ? GetSubfolders(path) : await GetSubfoldersAsync(path); +#else + var childFolders = await GetSubfoldersAsync(path); +#endif // Fall back to StorageFolder API for non-filesystem paths (e.g. FTP) if (childFolders is null) @@ -827,56 +829,6 @@ public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem p } } - /// - /// Enumerates subfolders using Win32 API, including hidden folders based on user settings. - /// Returns null if the path cannot be enumerated with Win32. - /// - private unsafe List<(string Name, string Path, bool IsHidden)>? GetSubfolders(string parentPath) - { - WIN32_FIND_DATAW findData = default; - using FindCloseSafeHandle hFile = PInvoke.FindFirstFileEx( - $"{parentPath}{Path.DirectorySeparatorChar}*.*", - FINDEX_INFO_LEVELS.FindExInfoBasic, - &findData, - FINDEX_SEARCH_OPS.FindExSearchNameMatch, - FIND_FIRST_EX_FLAGS.FIND_FIRST_EX_LARGE_FETCH); - - if (hFile.IsInvalid) - return null; - - var showHidden = UserSettingsService.FoldersSettingsService.ShowHiddenItems; - var showSystem = UserSettingsService.FoldersSettingsService.ShowProtectedSystemFiles; - var showDot = UserSettingsService.FoldersSettingsService.ShowDotFiles; - var folders = new List<(string Name, string Path, bool IsHidden)>(); - - do - { - if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == 0) - continue; - - string fileName = findData.cFileName.ToString(); - if (fileName is "." or "..") - continue; - - bool isHidden = ((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) != 0; - bool isSystem = ((FileAttributes)findData.dwFileAttributes & FileAttributes.System) != 0; - - if (isHidden && (!showHidden || (isSystem && !showSystem))) - continue; - - if (fileName.StartsWith('.') && !showDot) - continue; - - folders.Add((fileName, Path.Combine(parentPath, fileName), isHidden)); - } - while (PInvoke.FindNextFile(hFile, out findData)); - - var naturalComparer = NaturalStringComparer.GetForProcessor(); - folders.Sort((a, b) => naturalComparer.Compare(a.Name, b.Name)); - - return folders; - } - private async Task LoadFlyoutItemIconAsync(MenuFlyoutItem flyoutItem, string path) { var imageSource = await NavigationHelpers.GetIconForPathAsync(path);