Skip to content

Code Quality: Simplified loading of logical drives and network locations in the Home widges #17102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Files.App.CsWin32/ManualGuid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public static Guid* IID_IStorageProviderStatusUISourceFactory

[GuidRVAGen.Guid("00021500-0000-0000-C000-000000000046")]
public static partial Guid* IID_IQueryInfo { get; }

[GuidRVAGen.Guid("000214F9-0000-0000-C000-000000000046")]
public static partial Guid* IID_IShellLinkW { get; }
}

public static unsafe partial class CLSID
Expand Down
3 changes: 3 additions & 0 deletions src/Files.App.CsWin32/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
GetKeyState
CreateDirectoryFromApp
WNetCancelConnection2
NET_USE_CONNECT_FLAGS

Check warning on line 48 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, x64)

Method, type or constant "NET_USE_CONNECT_FLAGS" not found

Check warning on line 48 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, x64)

Method, type or constant "NET_USE_CONNECT_FLAGS" not found

Check warning on line 48 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, arm64)

Method, type or constant "NET_USE_CONNECT_FLAGS" not found

Check warning on line 48 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, arm64)

Method, type or constant "NET_USE_CONNECT_FLAGS" not found
NETRESOURCEW
WNetAddConnection3
CREDENTIALW
Expand Down Expand Up @@ -78,7 +78,7 @@
SetEntriesInAcl
ACL_SIZE_INFORMATION
DeleteAce
EXPLICIT_ACCESS

Check warning on line 81 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, x64)

Method, type or constant "EXPLICIT_ACCESS" not found. Did you mean or "EXPLICIT_ACCESS_A" or "EXPLICIT_ACCESS_W"?

Check warning on line 81 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, x64)

Method, type or constant "EXPLICIT_ACCESS" not found. Did you mean or "EXPLICIT_ACCESS_A" or "EXPLICIT_ACCESS_W"?

Check warning on line 81 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, arm64)

Method, type or constant "EXPLICIT_ACCESS" not found. Did you mean or "EXPLICIT_ACCESS_A" or "EXPLICIT_ACCESS_W"?

Check warning on line 81 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, arm64)

Method, type or constant "EXPLICIT_ACCESS" not found. Did you mean or "EXPLICIT_ACCESS_A" or "EXPLICIT_ACCESS_W"?
ACCESS_ALLOWED_ACE
LookupAccountSid
GetComputerName
Expand Down Expand Up @@ -134,7 +134,7 @@
CoTaskMemFree
QueryDosDevice
DeviceIoControl
GetLastError

Check warning on line 137 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, x64)

This API will not be generated. Do not generate GetLastError. Call Marshal.GetLastWin32Error() instead. Learn more from https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error

Check warning on line 137 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, x64)

This API will not be generated. Do not generate GetLastError. Call Marshal.GetLastWin32Error() instead. Learn more from https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error

Check warning on line 137 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Debug, arm64)

This API will not be generated. Do not generate GetLastError. Call Marshal.GetLastWin32Error() instead. Learn more from https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error

Check warning on line 137 in src/Files.App.CsWin32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / build (Release, arm64)

This API will not be generated. Do not generate GetLastError. Call Marshal.GetLastWin32Error() instead. Learn more from https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error
CreateFile
GetVolumeInformation
COMPRESSION_FORMAT
Expand Down Expand Up @@ -226,3 +226,6 @@
RoGetAgileReference
IQueryInfo
QITIPF_FLAGS
GetDiskFreeSpaceEx
GetDriveType
SLGP_FLAGS
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

namespace Files.App.Storage
{
public interface IWindowsFile : IWindowsStorable, IChildFile
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

namespace Files.App.Storage
{
public interface IWindowsFolder : IWindowsStorable, IChildFolder
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Files.App.Storage
{
public interface IWindowsStorable : IDisposable
public interface IWindowsStorable : IStorableChild, IEquatable<IWindowsStorable>, IDisposable
{
ComPtr<IShellItem> ThisPtr { get; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Files.App.Storage
{
[DebuggerDisplay("{" + nameof(ToString) + "()}")]
public sealed class WindowsFile : WindowsStorable, IChildFile
public sealed class WindowsFile : WindowsStorable, IWindowsFile
{
public WindowsFile(ComPtr<IShellItem> nativeObject)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Files.App.Storage
{
[DebuggerDisplay("{" + nameof(ToString) + "()}")]
public sealed class WindowsFolder : WindowsStorable, IChildFolder
public sealed class WindowsFolder : WindowsStorable, IWindowsFolder
{
public WindowsFolder(ComPtr<IShellItem> nativeObject)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Files.App.Storage
{
public abstract class WindowsStorable : IWindowsStorable, IStorableChild, IEquatable<IWindowsStorable>
public abstract class WindowsStorable : IWindowsStorable
{
public ComPtr<IShellItem> ThisPtr { get; protected set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,19 @@ public unsafe static HRESULT TryGetShellTooltip(this IWindowsStorable storable,

return HRESULT.S_OK;
}

public unsafe static HRESULT TryGetShellLink(this IWindowsStorable storable, out ComPtr<IShellLinkW> pShellLink)
{
pShellLink = default;

using ComPtr<IShellLinkW> pShellLinkW = default;
HRESULT hr = storable.ThisPtr.Get()->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IShellLinkW, (void**)pShellLinkW.GetAddressOf());
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;

pShellLink = pShellLinkW;

return HRESULT.S_OK;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.NetworkManagement.WNet;
using Windows.Win32.Storage.FileSystem;
using Windows.Win32.UI.Shell;

Expand Down Expand Up @@ -84,5 +85,37 @@ public static bool TryShowFormatDriveDialog(HWND hWnd, uint driveLetterIndex, SH
var result = PInvoke.SHFormatDrive(hWnd, driveLetterIndex, id, options);
return result is 0xFFFF;
}

public static bool TryGetDriveTotalSpace(this IWindowsStorable storable, out ulong totalSize)
{
ulong ulTotalSize = 0UL;
bool res = PInvoke.GetDiskFreeSpaceEx(storable.GetDisplayName(), null, &ulTotalSize, null);

totalSize = ulTotalSize;

return res;
}

public static bool TryGetDriveFreeSpace(this IWindowsStorable storable, out ulong freeSize)
{
ulong ulFreeSize = 0UL;
bool res = PInvoke.GetDiskFreeSpaceEx(storable.GetDisplayName(), null, null, &ulFreeSize);

freeSize = ulFreeSize;

return res;
}

public static bool TryGetDriveType(this IWindowsStorable storable, out uint driveType)
{
driveType = PInvoke.GetDriveType(storable.GetDisplayName());

return driveType is 0U; // DRIVE_UNKNOWN
}

public static bool TryDisconnectNetworkDrive(this IWindowsStorable storable)
{
return PInvoke.WNetCancelConnection2W(storable.GetDisplayName().TrimEnd('\\'), NET_CONNECT_FLAGS.CONNECT_UPDATE_PROFILE, true) is WIN32_ERROR.NO_ERROR;
}
}
}
73 changes: 42 additions & 31 deletions src/Files.App/Data/Items/WidgetDriveCardItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,61 @@
// Licensed under the MIT License.

using Microsoft.UI.Xaml.Media.Imaging;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Shell;

namespace Files.App.Data.Items
{
public sealed partial class WidgetDriveCardItem : WidgetCardItem, IWidgetCardItem<DriveItem>, IComparable<WidgetDriveCardItem>
public sealed partial class WidgetDriveCardItem : WidgetCardItem, IWidgetCardItem<IWindowsFolder>, IDisposable
{
private byte[] thumbnailData;
// Properties

public new DriveItem Item { get; private set; }
public required new IWindowsFolder Item { get; set; }

private BitmapImage thumbnail;
public BitmapImage Thumbnail
{
get => thumbnail;
set => SetProperty(ref thumbnail, value);
}
public required string Text { get; set; }

public bool ShowStorageSense => UsedSize.GigaBytes / TotalSize.GigaBytes >= Constants.Widgets.Drives.LowStorageSpacePercentageThreshold;

public bool ShowDriveUsage => TotalSize.GigaBytes > 0D;

public ByteSizeLib.ByteSize TotalSize { get; set; } = default;

public ByteSizeLib.ByteSize FreeSize { get; set; } = default;

public ByteSizeLib.ByteSize UsedSize => ByteSizeLib.ByteSize.FromBytes(TotalSize.Bytes - FreeSize.Bytes);

public string? UsageText => string.Format(Strings.DriveFreeSpaceAndCapacity.GetLocalizedResource(), FreeSize.ToSizeString(), TotalSize.ToSizeString());

public required SystemIO.DriveType DriveType { get; set; }

public WidgetDriveCardItem(DriveItem item)
private BitmapImage? _Thumbnail;
public BitmapImage? Thumbnail { get => _Thumbnail; set => SetProperty(ref _Thumbnail, value); }

// Constructor

public WidgetDriveCardItem()
{
Item = item;
Path = item.Path;
}

// Methods

public async Task LoadCardThumbnailAsync()
{
var result = await FileThumbnailHelper.GetIconAsync(
Item.Path,
Constants.ShellIconSizes.Large,
true,
IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);

if (result is null)
{
using var thumbnail = await DriveHelpers.GetThumbnailAsync(Item.Root);
result ??= await thumbnail.ToByteArrayAsync();
}

thumbnailData = result;

var bitmapImage = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => thumbnailData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal);
if (bitmapImage is not null)
Thumbnail = bitmapImage;
if (string.IsNullOrEmpty(Path) || Item is not IWindowsStorable windowsStorable)
return;

HRESULT hr = windowsStorable.TryGetThumbnail((int)(Constants.ShellIconSizes.Large * App.AppModel.AppWindowDPI), SIIGBF.SIIGBF_ICONONLY, out var rawThumbnailData);
if (hr.Failed || rawThumbnailData is null)
return;

Thumbnail = await rawThumbnailData.ToBitmapAsync();
}

public int CompareTo(WidgetDriveCardItem? other)
=> Item.Path.CompareTo(other?.Item?.Path);
// Disposer

public void Dispose()
{
Item.Dispose();
}
}
}
24 changes: 12 additions & 12 deletions src/Files.App/UserControls/Widgets/DrivesWidget.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AutomationProperties.Name="{x:Bind Item.Text, Mode=OneWay}"
AutomationProperties.Name="{x:Bind Text, Mode=OneWay}"
Click="Button_Click"
CornerRadius="{StaticResource ControlCornerRadius}"
DataContext="{x:Bind}"
PointerPressed="Button_PointerPressed"
RightTapped="Button_RightTapped"
Tag="{x:Bind Item.Path}"
ToolTipService.ToolTip="{x:Bind Item.Text, Mode=OneWay}">
Tag="{x:Bind Path}"
ToolTipService.ToolTip="{x:Bind Text, Mode=OneWay}">
<Grid
Margin="8"
HorizontalAlignment="Stretch"
Expand Down Expand Up @@ -75,7 +75,7 @@
VerticalAlignment="Center"
FontSize="14"
FontWeight="Medium"
Text="{x:Bind Item.Text, Mode=OneWay}"
Text="{x:Bind Text, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />

Expand All @@ -85,10 +85,10 @@
Grid.Column="1"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
x:Load="{x:Bind Item.ShowDriveDetails, Mode=OneWay}"
x:Load="{x:Bind ShowDriveUsage, Mode=OneWay}"
AutomationProperties.AccessibilityView="Raw"
Maximum="{x:Bind Item.MaxSpace.GigaBytes, Mode=OneWay}"
Value="{x:Bind Item.SpaceUsed.GigaBytes, Mode=OneWay}" />
Maximum="{x:Bind TotalSize.GigaBytes, Mode=OneWay}"
Value="{x:Bind UsedSize.GigaBytes, Mode=OneWay}" />

<Button
x:Name="GoToStorageSense"
Expand All @@ -100,12 +100,12 @@
Padding="0"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
x:Load="{x:Bind Item.ShowStorageSense, Mode=OneWay}"
x:Load="{x:Bind ShowStorageSense, Mode=OneWay}"
AutomationProperties.Name="{helpers:ResourceString Name=OpenStorageSense}"
Background="Transparent"
BorderBrush="Transparent"
Click="GoToStorageSense_Click"
Tag="{x:Bind Item.Path}"
Tag="{x:Bind Path}"
ToolTipService.ToolTip="{helpers:ResourceString Name=OpenStorageSense}">
<FontIcon
HorizontalAlignment="Center"
Expand All @@ -121,13 +121,13 @@
Grid.ColumnSpan="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
x:Load="{x:Bind Item.ShowDriveDetails, Mode=OneWay}"
x:Load="{x:Bind ShowDriveUsage, Mode=OneWay}"
x:Phase="1"
FontSize="12"
Text="{x:Bind Item.SpaceText, Mode=OneWay}"
Text="{x:Bind UsageText, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
ToolTipService.ToolTip="{x:Bind Item.SpaceText, Mode=OneWay}" />
ToolTipService.ToolTip="{x:Bind UsageText, Mode=OneWay}" />
</Grid>
</Button>
</DataTemplate>
Expand Down
20 changes: 10 additions & 10 deletions src/Files.App/UserControls/Widgets/NetworkLocationsWidget.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AutomationProperties.Name="{x:Bind Item.Text, Mode=OneWay}"
AutomationProperties.Name="{x:Bind Text, Mode=OneWay}"
Click="Button_Click"
CornerRadius="{StaticResource ControlCornerRadius}"
DataContext="{x:Bind}"
PointerPressed="Button_PointerPressed"
RightTapped="Button_RightTapped"
Tag="{x:Bind Item.Path}"
ToolTipService.ToolTip="{x:Bind Item.Text, Mode=OneWay}">
Tag="{x:Bind Path}"
ToolTipService.ToolTip="{x:Bind Text, Mode=OneWay}">
<Grid
Margin="8"
HorizontalAlignment="Stretch"
Expand Down Expand Up @@ -101,7 +101,7 @@
VerticalAlignment="Center"
FontSize="14"
FontWeight="Medium"
Text="{x:Bind Item.Text, Mode=OneWay}"
Text="{x:Bind Text, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />

Expand All @@ -111,24 +111,24 @@
Grid.Column="1"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
x:Load="{x:Bind Item.ShowDriveDetails, Mode=OneWay}"
x:Load="{x:Bind ShowDriveUsage, Mode=OneWay}"
AutomationProperties.AccessibilityView="Raw"
Maximum="{x:Bind Item.MaxSpace.GigaBytes, Mode=OneWay}"
Value="{x:Bind Item.SpaceUsed.GigaBytes, Mode=OneWay}" />
Maximum="{x:Bind TotalSize.GigaBytes, Mode=OneWay}"
Value="{x:Bind UsedSize.GigaBytes, Mode=OneWay}" />

<TextBlock
x:Name="DriveSpaceTextBlock"
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
x:Load="{x:Bind Item.ShowDriveDetails, Mode=OneWay}"
x:Load="{x:Bind ShowDriveUsage, Mode=OneWay}"
x:Phase="1"
FontSize="12"
Text="{x:Bind Item.SpaceText, Mode=OneWay}"
Text="{x:Bind UsageText, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
ToolTipService.ToolTip="{x:Bind Item.SpaceText, Mode=OneWay}" />
ToolTipService.ToolTip="{x:Bind UsageText, Mode=OneWay}" />
</Grid>
</Button>
</DataTemplate>
Expand Down
Loading
Loading