diff --git a/src/Files.App/Data/Items/ListedItem.cs b/src/Files.App/Data/Items/ListedItem.cs index c340a0eb1a90..4968d3d6e211 100644 --- a/src/Files.App/Data/Items/ListedItem.cs +++ b/src/Files.App/Data/Items/ListedItem.cs @@ -374,6 +374,7 @@ public override string ToString() public bool IsAlternateStream => this is AlternateStreamItem; public bool IsGitItem => this is GitItem; public virtual bool IsExecutable => FileExtensionHelpers.IsExecutableFile(ItemPath); + public virtual bool IsPythonFile => FileExtensionHelpers.IsPythonFile(ItemPath); public bool IsPinned => App.QuickAccessManager.Model.FavoriteItems.Contains(itemPath); public bool IsDriveRoot => ItemPath == PathNormalization.GetPathRoot(ItemPath); public bool IsElevated => CheckElevationRights(); diff --git a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs index d6cb86a7e012..e718cb75fc5f 100644 --- a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs +++ b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs @@ -83,7 +83,7 @@ public static async Task OpenSelectedItemsAsync(IShellPage associatedInstance, b public static async Task OpenItemsWithExecutableAsync(IShellPage associatedInstance, IEnumerable items, string executable) { - // Don't open files and folders inside recycle bin + // Don't open files and folders inside recycle bin if (associatedInstance.FilesystemViewModel.WorkingDirectory.StartsWith(Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.Ordinal) || associatedInstance.SlimContentPage is null) { @@ -104,6 +104,21 @@ public static async Task OpenItemsWithExecutableAsync(IShellPage associatedInsta } } + public static async Task OpenItemsWithPythonAsync(IShellPage associatedInstance, IEnumerable items, string pythonScriptPath) + { + // Don't open files and folders inside recycle bin + if (associatedInstance.FilesystemViewModel.WorkingDirectory.StartsWith(Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.Ordinal) || + associatedInstance.SlimContentPage is null) + { + return; + } + + foreach (var item in items) + { + await Win32Helpers.InvokeWin32ComponentAsync(pythonScriptPath, associatedInstance, arguments: $"\"{item.Path}\""); + } + } + /// /// Navigates to a directory or opens file /// diff --git a/src/Files.App/Utils/Storage/Operations/FilesystemHelpers.cs b/src/Files.App/Utils/Storage/Operations/FilesystemHelpers.cs index e9b0a3109b35..22fc6d54b7fd 100644 --- a/src/Files.App/Utils/Storage/Operations/FilesystemHelpers.cs +++ b/src/Files.App/Utils/Storage/Operations/FilesystemHelpers.cs @@ -231,7 +231,8 @@ public async Task PerformOperationTypeAsync( string destination, bool showDialog, bool registerHistory, - bool isTargetExecutable = false) + bool isTargetExecutable = false, + bool isTargetPythonFile = false) { try { @@ -260,6 +261,12 @@ public async Task PerformOperationTypeAsync( NavigationHelpers.OpenItemsWithExecutableAsync(associatedInstance, items, destination); return ReturnResult.Success; } + else if (isTargetPythonFile) + { + var items = await GetDraggedStorageItems(packageView); + NavigationHelpers.OpenItemsWithPythonAsync(associatedInstance, items, destination); + return ReturnResult.Success; + } else { return await CreateShortcutFromClipboard(packageView, destination, showDialog, registerHistory); diff --git a/src/Files.App/Utils/Storage/Operations/IFilesystemHelpers.cs b/src/Files.App/Utils/Storage/Operations/IFilesystemHelpers.cs index 083e323b4c2f..204e592b7434 100644 --- a/src/Files.App/Utils/Storage/Operations/IFilesystemHelpers.cs +++ b/src/Files.App/Utils/Storage/Operations/IFilesystemHelpers.cs @@ -114,7 +114,7 @@ public interface IFilesystemHelpers : IDisposable /// The is NOT fullPath /// Determines whether is saved /// of performed operation - Task PerformOperationTypeAsync(DataPackageOperation operation, DataPackageView packageView, string destination, bool showDialog, bool registerHistory, bool isDestinationExecutable = false); + Task PerformOperationTypeAsync(DataPackageOperation operation, DataPackageView packageView, string destination, bool showDialog, bool registerHistory, bool isDestinationExecutable = false, bool isDestinationPython = false); #region Copy diff --git a/src/Files.App/Views/Layouts/BaseLayoutPage.cs b/src/Files.App/Views/Layouts/BaseLayoutPage.cs index 74ca24f67766..515b3274bf7f 100644 --- a/src/Files.App/Views/Layouts/BaseLayoutPage.cs +++ b/src/Files.App/Views/Layouts/BaseLayoutPage.cs @@ -1034,7 +1034,7 @@ private async void Item_DragOver(object sender, DragEventArgs e) { e.DragUIOverride.IsCaptionVisible = true; - if (item.IsExecutable) + if (item.IsExecutable || item.IsPythonFile) { e.DragUIOverride.Caption = $"{"OpenWith".GetLocalizedResource()} {item.Name}"; e.AcceptedOperation = DataPackageOperation.Link; @@ -1112,7 +1112,7 @@ private async void Item_Drop(object sender, DragEventArgs e) var item = GetItemFromElement(sender); if (item is not null) - await ParentShellPageInstance!.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.DataView, (item as ShortcutItem)?.TargetPath ?? item.ItemPath, false, true, item.IsExecutable); + await ParentShellPageInstance!.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.DataView, (item as ShortcutItem)?.TargetPath ?? item.ItemPath, false, true, item.IsExecutable, item.IsPythonFile); deferral.Complete(); } @@ -1257,7 +1257,7 @@ protected void InitializeDrag(UIElement container, ListedItem item) return; UninitializeDrag(container); - if ((item.PrimaryItemAttribute == StorageItemTypes.Folder && !RecycleBinHelpers.IsPathUnderRecycleBin(item.ItemPath)) || item.IsExecutable) + if ((item.PrimaryItemAttribute == StorageItemTypes.Folder && !RecycleBinHelpers.IsPathUnderRecycleBin(item.ItemPath)) || item.IsExecutable || item.IsPythonFile) { container.AllowDrop = true; container.AddHandler(UIElement.DragOverEvent, Item_DragOverEventHandler, true); diff --git a/src/Files.Shared/Helpers/FileExtensionHelpers.cs b/src/Files.Shared/Helpers/FileExtensionHelpers.cs index 1bd0230cbeed..99a7ef93367e 100644 --- a/src/Files.Shared/Helpers/FileExtensionHelpers.cs +++ b/src/Files.Shared/Helpers/FileExtensionHelpers.cs @@ -206,5 +206,16 @@ public static bool IsCertificateFile(string? filePathToCheck) { return HasExtension(filePathToCheck, ".cer", ".crt", ".der", ".pfx"); } + + /// + /// Check if the file extension is a Python file. + /// + /// + /// true if the filePathToCheck is a python file; otherwise, false. + public static bool IsPythonFile(string? filePathToCheck) + { + return HasExtension(filePathToCheck, ".py"); + } + } }