Skip to content

Commit aca6998

Browse files
authored
Merge branch 'main' into Select_Item_On_Hover_#3682
2 parents 7b83255 + 8362873 commit aca6998

File tree

20 files changed

+1513
-1643
lines changed

20 files changed

+1513
-1643
lines changed

src/Files.App/App.xaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ await Task.WhenAll(
206206
SidebarPinnedController.InitializeAsync()
207207
);
208208
await Task.WhenAll(
209-
AppSettings.DetectQuickLook(),
210209
TerminalController.InitializeAsync(),
211210
JumpList.InitializeAsync(),
212211
ExternalResourcesHelper.LoadOtherThemesAsync(),

src/Files.App/DataModels/AppModel.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ public bool MultiselectEnabled
8989
set => SetProperty(ref multiselectEnabled, value);
9090
}
9191

92-
private bool isQuickLookSupported;
93-
public bool IsQuickLookSupported
92+
private bool isQuickLookAvailable;
93+
public bool IsQuickLookAvailable
9494
{
95-
get => isQuickLookSupported;
96-
set => SetProperty(ref isQuickLookSupported, value);
95+
get => isQuickLookAvailable;
96+
set => SetProperty(ref isQuickLookAvailable, value);
9797
}
9898

9999
private FontFamily symbolFontFamily;

src/Files.App/Files.App.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@
152152
<PackageReference Include="Microsoft.AppCenter.Analytics" Version="4.5.3" />
153153
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.3" />
154154
<PackageReference Include="Microsoft.Data.Sqlite.Core">
155-
<Version>6.0.8</Version>
155+
<Version>6.0.9</Version>
156156
</PackageReference>
157157
<PackageReference Include="Microsoft.Extensions.DependencyInjection">
158158
<Version>6.0.0</Version>

src/Files.App/Helpers/DriveHelpers.cs

Lines changed: 15 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,29 @@
1-
using Files.App.Interacts;
2-
using Files.App.Extensions;
3-
using System.Diagnostics;
1+
using Files.App.Interacts;
42
using System.Threading.Tasks;
5-
using Windows.UI.Notifications;
6-
using CommunityToolkit.WinUI.Notifications;
7-
using Files.App.Shell;
3+
using Microsoft.Management.Infrastructure;
84

95
namespace Files.App.Helpers
106
{
117
public static class DriveHelpers
128
{
13-
// Eject using Shell Verb (fixes #6072, #6439)
14-
public static Task EjectDeviceAsync(string path)
15-
=> ContextMenu.InvokeVerb("eject", path);
16-
17-
// Eject using DeviceIoControl
18-
/*public static async Task EjectDeviceAsync(string path)
9+
public static async Task<bool> EjectDeviceAsync(string path)
1910
{
2011
var removableDevice = new RemovableDevice(path);
21-
bool result = await removableDevice.EjectAsync();
22-
if (result)
23-
{
24-
Debug.WriteLine("Device successfully ejected");
12+
return await removableDevice.EjectAsync();
13+
}
2514

26-
var toastContent = new ToastContent()
27-
{
28-
Visual = new ToastVisual()
29-
{
30-
BindingGeneric = new ToastBindingGeneric()
31-
{
32-
Children =
33-
{
34-
new AdaptiveText()
35-
{
36-
Text = "EjectNotificationHeader".GetLocalizedResource()
37-
},
38-
new AdaptiveText()
39-
{
40-
Text = "EjectNotificationBody".GetLocalizedResource()
41-
}
42-
},
43-
Attribution = new ToastGenericAttributionText()
44-
{
45-
Text = "SettingsAboutAppName".GetLocalizedResource()
46-
}
47-
}
48-
},
49-
ActivationType = ToastActivationType.Protocol
50-
};
51-
52-
// Create the toast notification
53-
var toastNotif = new ToastNotification(toastContent.GetXml());
15+
public static string GetVolumeId(string driveName)
16+
{
17+
string name = driveName.ToUpperInvariant();
18+
string query = $"SELECT DeviceID FROM Win32_Volume WHERE DriveLetter = '{name}'";
5419

55-
// And send the notification
56-
ToastNotificationManager.CreateToastNotifier().Show(toastNotif);
57-
}
58-
else
20+
using var cimSession = CimSession.Create(null);
21+
foreach (var item in cimSession.QueryInstances(@"root\cimv2", "WQL", query)) // max 1 result because DriveLetter is unique.
5922
{
60-
Debug.WriteLine("Can't eject device");
61-
62-
await DialogDisplayHelper.ShowDialogAsync(
63-
"EjectNotificationErrorDialogHeader".GetLocalizedResource(),
64-
"EjectNotificationErrorDialogBody".GetLocalizedResource());
23+
return (string)item.CimInstanceProperties["DeviceID"]?.Value ?? string.Empty;
6524
}
66-
}*/
25+
26+
return string.Empty;
27+
}
6728
}
6829
}
Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,79 @@
1-
using Files.Shared.Extensions;
2-
using System.Diagnostics;
1+
using System;
2+
using System.IO;
3+
using System.IO.Pipes;
4+
using System.Security.Principal;
35
using System.Threading.Tasks;
4-
using Windows.Foundation.Collections;
56

6-
namespace Files.App.Helpers
7+
namespace Files.App.Helpers;
8+
9+
public static class QuickLookHelpers
710
{
8-
public static class QuickLookHelpers
9-
{
10-
public static async Task ToggleQuickLook(IShellPage associatedInstance, bool switchPreview = false)
11-
{
12-
if (!App.AppModel.IsQuickLookSupported || !associatedInstance.SlimContentPage.IsItemSelected || associatedInstance.SlimContentPage.IsRenamingItem)
13-
{
14-
return;
15-
}
16-
17-
await SafetyExtensions.IgnoreExceptions(async () =>
18-
{
19-
Debug.WriteLine("Toggle QuickLook");
20-
var connection = await AppServiceConnectionHelper.Instance;
21-
22-
if (connection != null)
23-
{
24-
await connection.SendMessageAsync(new ValueSet()
25-
{
26-
{ "path", associatedInstance.SlimContentPage.SelectedItem.ItemPath },
27-
{ "switch", switchPreview },
28-
{ "Arguments", "ToggleQuickLook" }
29-
});
30-
}
31-
32-
}, App.Logger);
33-
}
34-
}
11+
private const int TIMEOUT = 500;
12+
13+
public static async Task ToggleQuickLook(IShellPage associatedInstance, bool switchPreview = false)
14+
{
15+
if (!associatedInstance.SlimContentPage.IsItemSelected || associatedInstance.SlimContentPage.IsRenamingItem)
16+
return;
17+
18+
App.AppModel.IsQuickLookAvailable = await DetectQuickLookAvailability();
19+
20+
if (App.AppModel.IsQuickLookAvailable == false)
21+
return;
22+
23+
string pipeName = $"QuickLook.App.Pipe.{WindowsIdentity.GetCurrent().User?.Value}";
24+
string message = switchPreview ? "QuickLook.App.PipeMessages.Switch" : "QuickLook.App.PipeMessages.Toggle";
25+
26+
await using var client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
27+
try
28+
{
29+
await client.ConnectAsync(TIMEOUT);
30+
31+
await using var writer = new StreamWriter(client);
32+
await writer.WriteLineAsync($"{message}|{associatedInstance.SlimContentPage.SelectedItem.ItemPath}");
33+
await writer.FlushAsync();
34+
}
35+
catch (TimeoutException)
36+
{
37+
client.Close();
38+
}
39+
}
40+
41+
private static async Task<bool> DetectQuickLookAvailability()
42+
{
43+
static async Task<int> QuickLookServerAvailable()
44+
{
45+
string pipeName = $"QuickLook.App.Pipe.{WindowsIdentity.GetCurrent().User?.Value}";
46+
string pipeSwitch = "QuickLook.App.PipeMessages.Switch";
47+
48+
await using var client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
49+
try
50+
{
51+
await client.ConnectAsync(TIMEOUT);
52+
var serverInstances = client.NumberOfServerInstances;
53+
54+
await using var writer = new StreamWriter(client);
55+
await writer.WriteLineAsync($"{pipeSwitch}|");
56+
await writer.FlushAsync();
57+
58+
return serverInstances;
59+
}
60+
catch (TimeoutException)
61+
{
62+
client.Close();
63+
return 0;
64+
}
65+
}
66+
67+
try
68+
{
69+
var result = await QuickLookServerAvailable();
70+
App.Logger.Info($"QuickLook detected: {result != 0}");
71+
return result != 0;
72+
}
73+
catch (Exception ex)
74+
{
75+
App.Logger.Info(ex, ex.Message);
76+
return false;
77+
}
78+
}
3579
}

src/Files.App/Helpers/UIHelpers.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,69 @@
99
using Microsoft.UI.Xaml.Media;
1010
using Microsoft.UI.Xaml.Media.Imaging;
1111
using Files.App.Shell;
12+
using System.Diagnostics;
13+
using CommunityToolkit.WinUI.Notifications;
14+
using Windows.UI.Notifications;
15+
using Files.App.Extensions;
1216

1317
namespace Files.App.Helpers
1418
{
1519
public static class UIHelpers
1620
{
21+
/// <summary>
22+
/// Displays a toast or dialog to indicate the result of
23+
/// a device ejection operation.
24+
/// </summary>
25+
/// <param name="result">Only true implies a successful device ejection</param>
26+
/// <returns></returns>
27+
public static async Task ShowDeviceEjectResultAsync(bool result)
28+
{
29+
if (result)
30+
{
31+
Debug.WriteLine("Device successfully ejected");
32+
33+
var toastContent = new ToastContent()
34+
{
35+
Visual = new ToastVisual()
36+
{
37+
BindingGeneric = new ToastBindingGeneric()
38+
{
39+
Children =
40+
{
41+
new AdaptiveText()
42+
{
43+
Text = "EjectNotificationHeader".GetLocalizedResource()
44+
},
45+
new AdaptiveText()
46+
{
47+
Text = "EjectNotificationBody".GetLocalizedResource()
48+
}
49+
},
50+
Attribution = new ToastGenericAttributionText()
51+
{
52+
Text = "SettingsAboutAppName".GetLocalizedResource()
53+
}
54+
}
55+
},
56+
ActivationType = ToastActivationType.Protocol
57+
};
58+
59+
// Create the toast notification
60+
var toastNotif = new ToastNotification(toastContent.GetXml());
61+
62+
// And send the notification
63+
ToastNotificationManager.CreateToastNotifier().Show(toastNotif);
64+
}
65+
else
66+
{
67+
Debug.WriteLine("Can't eject device");
68+
69+
await DialogDisplayHelper.ShowDialogAsync(
70+
"EjectNotificationErrorDialogHeader".GetLocalizedResource(),
71+
"EjectNotificationErrorDialogBody".GetLocalizedResource());
72+
}
73+
}
74+
1775
public static async Task<ContentDialogResult> TryShowAsync(this ContentDialog dialog)
1876
{
1977
try
Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,21 @@
11
using Files.Backend.Models;
22
using Files.Backend.Services;
3-
using Files.Shared.Extensions;
43
using Files.App.Helpers;
54
using System.Threading.Tasks;
6-
using Windows.ApplicationModel.AppService;
7-
using Windows.Foundation.Collections;
85

96
namespace Files.App.ServicesImplementation
107
{
118
internal class VolumeInfoFactory : IVolumeInfoFactory
129
{
13-
public async Task<VolumeInfo> BuildVolumeInfo(string driveName)
10+
public VolumeInfo BuildVolumeInfo(string driveName)
1411
{
15-
string volumeId = await GetVolumeID(driveName);
12+
string volumeId = GetVolumeID(driveName);
1613
return new VolumeInfo(volumeId);
1714
}
1815

19-
private async Task<string> GetVolumeID(string driveName)
16+
private string GetVolumeID(string driveName)
2017
{
21-
var connection = await AppServiceConnectionHelper.Instance;
22-
if (connection is null)
23-
{
24-
return string.Empty;
25-
}
26-
27-
var parameter = new ValueSet
28-
{
29-
["Arguments"] = "VolumeID",
30-
["DriveName"] = driveName,
31-
};
32-
33-
var (status, response) = await connection.SendMessageForResponseAsync(parameter);
34-
if (status is AppServiceResponseStatus.Success)
35-
{
36-
return response.Get("VolumeID", string.Empty);
37-
}
38-
39-
return string.Empty;
18+
return DriveHelpers.GetVolumeId(driveName);
4019
}
4120
}
4221
}

src/Files.App/UserControls/SidebarControl.xaml.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
using CommunityToolkit.WinUI.UI;
3030
using Microsoft.UI.Input;
3131
using UWPToWinAppSDKUpgradeHelpers;
32-
using Windows.ApplicationModel.Search.Core;
32+
using Vanara.PInvoke;
3333

3434
namespace Files.App.UserControls
3535
{
@@ -503,7 +503,8 @@ private void OpenProperties(CommandBarFlyout menu)
503503

504504
private async void EjectDevice()
505505
{
506-
await DriveHelpers.EjectDeviceAsync(rightClickedItem.Path);
506+
var result = await DriveHelpers.EjectDeviceAsync(rightClickedItem.Path);
507+
await UIHelpers.ShowDeviceEjectResultAsync(result);
507508
}
508509

509510
private async void Sidebar_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
@@ -1159,7 +1160,8 @@ private async Task<bool> CheckEmptyDrive(string drivePath)
11591160
bool ejectButton = await DialogDisplayHelper.ShowDialogAsync("InsertDiscDialog/Title".GetLocalizedResource(), string.Format("InsertDiscDialog/Text".GetLocalizedResource(), matchingDrive.Path), "InsertDiscDialog/OpenDriveButton".GetLocalizedResource(), "Close".GetLocalizedResource());
11601161
if (ejectButton)
11611162
{
1162-
await DriveHelpers.EjectDeviceAsync(matchingDrive.Path);
1163+
var result = await DriveHelpers.EjectDeviceAsync(matchingDrive.Path);
1164+
await UIHelpers.ShowDeviceEjectResultAsync(result);
11631165
}
11641166
return true;
11651167
}

0 commit comments

Comments
 (0)