diff --git a/.github/workflows/deploy-preview-legacy.yml b/.github/workflows/deploy-preview-legacy.yml index cf3c6cc7572b..904117f8b793 100644 --- a/.github/workflows/deploy-preview-legacy.yml +++ b/.github/workflows/deploy-preview-legacy.yml @@ -48,6 +48,12 @@ jobs: $xmlDoc.Package.Identity.Publisher="$env:SIDELOAD_PUBLISHER_SECRET" $xmlDoc.Package.Properties.DisplayName="Files - Preview" $xmlDoc.Package.Applications.Application.VisualElements.DisplayName="Files - Preview" + $nsmgr = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable) + $nsmgr.AddNamespace("pkg", "http://schemas.microsoft.com/appx/manifest/foundation/windows10") + $alias = $xmlDoc.SelectSingleNode("/pkg:Package/pkg:Applications/pkg:Application/pkg:Extensions/uap5:Extension[@Name='windows.protocol']", $nsmgr) + $alias.Value="files-pre.exe" + $uriScheme = $xmlDoc.SelectSingleNode("/pkg:Package/pkg:Applications/pkg:Application/pkg:Extensions/uap5:Extension[@Name='windows.appExecutionAlias']", $nsmgr) + $uriScheme.Value="files-pre:" $xmlDoc.Save("$env:PACKAGE_PROJECT_DIR\Package.appxmanifest") env: SIDELOAD_PUBLISHER_SECRET: ${{ secrets.SIDELOAD_PUBLISHER_SECRET }} @@ -94,6 +100,26 @@ jobs: env: GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + - name: Inject the application execution alias + run: | + Get-ChildItem "$env:WORKING_DIR\src" -Include *.cs -recurse | ForEach-Object -Process ` + { ` + (Get-Content $_ -Raw | ForEach-Object -Process { $_ -replace "files.alias.key", "files-pre.exe" }) | ` + Set-Content $_ -NoNewline ` + } + env: + GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + + - name: Inject the application URI scheme + run: | + Get-ChildItem "$env:WORKING_DIR\src" -Include *.cs -recurse | ForEach-Object -Process ` + { ` + (Get-Content $_ -Raw | ForEach-Object -Process { $_ -replace "files.urischeme.key", "files-pre:" }) | ` + Set-Content $_ -NoNewline ` + } + env: + GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + - name: Use Windows SDK Preview shell: cmd run: | diff --git a/.github/workflows/deploy-stable-legacy.yml b/.github/workflows/deploy-stable-legacy.yml index 64dc136979d9..59ca264691b5 100644 --- a/.github/workflows/deploy-stable-legacy.yml +++ b/.github/workflows/deploy-stable-legacy.yml @@ -48,6 +48,12 @@ jobs: $xmlDoc.Package.Identity.Publisher="$env:SIDELOAD_PUBLISHER_SECRET" $xmlDoc.Package.Properties.DisplayName="Files" $xmlDoc.Package.Applications.Application.VisualElements.DisplayName="Files" + $nsmgr = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable) + $nsmgr.AddNamespace("pkg", "http://schemas.microsoft.com/appx/manifest/foundation/windows10") + $alias = $xmlDoc.SelectSingleNode("/pkg:Package/pkg:Applications/pkg:Application/pkg:Extensions/uap5:Extension[@Name='windows.appExecutionAlias']", $nsmgr) + $alias.Value="files.exe" + $alias = $xmlDoc.SelectSingleNode("/pkg:Package/pkg:Applications/pkg:Application/pkg:Extensions/uap5:Extension[@Name='windows.protocol']", $nsmgr) + $alias.Value="files-pre.exe" $xmlDoc.Save("$env:PACKAGE_PROJECT_DIR\Package.appxmanifest") env: SIDELOAD_PUBLISHER_SECRET: ${{ secrets.SIDELOAD_PUBLISHER_SECRET }} @@ -94,6 +100,26 @@ jobs: env: GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + - name: Inject the application execution alias + run: | + Get-ChildItem "$env:WORKING_DIR\src" -Include *.cs -recurse | ForEach-Object -Process ` + { ` + (Get-Content $_ -Raw | ForEach-Object -Process { $_ -replace "files.alias.key", "files.exe" }) | ` + Set-Content $_ -NoNewline ` + } + env: + GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + + - name: Inject the application URI scheme + run: | + Get-ChildItem "$env:WORKING_DIR\src" -Include *.cs -recurse | ForEach-Object -Process ` + { ` + (Get-Content $_ -Raw | ForEach-Object -Process { $_ -replace "files.urischeme.key", "files:" }) | ` + Set-Content $_ -NoNewline ` + } + env: + GH_OAUTH_CLIENT_ID: ${{ secrets.GH_OAUTH_CLIENT_ID }} + - name: Use Windows SDK Preview shell: cmd run: | diff --git a/src/Files.App (Package)/Package.appxmanifest b/src/Files.App (Package)/Package.appxmanifest index 1fa1a0246ad8..360342ce8472 100644 --- a/src/Files.App (Package)/Package.appxmanifest +++ b/src/Files.App (Package)/Package.appxmanifest @@ -119,12 +119,12 @@ - + - + diff --git a/src/Files.App/Actions/Navigation/OpenInNewWindowItemAction.cs b/src/Files.App/Actions/Navigation/OpenInNewWindowItemAction.cs index 0731ac707b3d..66949bb597e1 100644 --- a/src/Files.App/Actions/Navigation/OpenInNewWindowItemAction.cs +++ b/src/Files.App/Actions/Navigation/OpenInNewWindowItemAction.cs @@ -48,7 +48,7 @@ public async Task ExecuteAsync(object? parameter = null) foreach (ListedItem listedItem in items) { var selectedItemPath = (listedItem as ShortcutItem)?.TargetPath ?? listedItem.ItemPath; - var folderUri = new Uri($"files-uwp:?folder={@selectedItemPath}"); + var folderUri = new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable + $"?folder={@selectedItemPath}"); await Launcher.LaunchUriAsync(folderUri); } diff --git a/src/Files.App/Constants.cs b/src/Files.App/Constants.cs index 92dbb2a85660..ddec4461fbd7 100644 --- a/src/Files.App/Constants.cs +++ b/src/Files.App/Constants.cs @@ -26,6 +26,27 @@ public static class AutomatedWorkflowInjectionKeys public const string GitHubClientId = "githubclientid.secret"; public const string BingMapsSecret = "bingmapskey.secret"; + + public const string FilesExecutionAliasVariable = "files.alias.key"; + + public const string FilesExecutionAliasVariableEscaped = "files/alias/key"; + + public const string FilesExecutionAliasStaticStable = "files.exe"; + + public const string FilesExecutionAliasStaticPreview = "files-pre.exe"; + + public const string FilesExecutionAliasStaticDev = "files-dev.exe"; + + public const string FilesUriSchemaVariable = "files.urischeme.key"; + + public const string FilesUriSchemaVariableEscaped = "files/urischeme/key"; + + public const string FilesUriSchemaStaticStable = "files:"; + + public const string FilesUriSchemaStaticPreview = "files-pre:"; + + public const string FilesUriSchemaStaticDev = "files-dev:"; + } public static class KnownImageFormats diff --git a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs index 67fb24dc9542..6b03c0dcbb9c 100644 --- a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs +++ b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs @@ -58,6 +58,16 @@ public static class AppLifecycleHelper _ => Constants.AssetPaths.StableLogo }); + public static string AppExecutionAlias { get; } = + Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasVariable == Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasVariableEscaped.Replace('/', '.') + ? Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasStaticDev + : Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasVariable; + + public static string AppURIScheme { get; } = + Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable == Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariableEscaped.Replace('/', '.') + ? Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaStaticDev + : Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable; + /// /// Initializes the app components. /// @@ -359,7 +369,7 @@ public static void HandleAppUnhandledException(Exception? ex, bool showToastNoti // Try to re-launch and start over MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => { - await Launcher.LaunchUriAsync(new Uri("files-uwp:")); + await Launcher.LaunchUriAsync(new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable)); }) .Wait(100); } diff --git a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs index 0e962f49b3ae..37c8b4b5d3f0 100644 --- a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs +++ b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs @@ -250,14 +250,14 @@ public static Task OpenPathInNewWindowAsync(string? path) if (string.IsNullOrWhiteSpace(path)) return Task.FromResult(false); - var folderUri = new Uri($"files-uwp:?folder={Uri.EscapeDataString(path)}"); + var folderUri = new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable + $"?folder={Uri.EscapeDataString(path)}"); return Launcher.LaunchUriAsync(folderUri).AsTask(); } public static Task OpenTabInNewWindowAsync(string tabArgs) { - var folderUri = new Uri($"files-uwp:?tab={Uri.EscapeDataString(tabArgs)}"); + var folderUri = new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable + $"?tab={Uri.EscapeDataString(tabArgs)}"); return Launcher.LaunchUriAsync(folderUri).AsTask(); } @@ -271,7 +271,7 @@ public static void OpenInSecondaryPane(IShellPage associatedInstance, ListedItem public static Task LaunchNewWindowAsync() { - var filesUWPUri = new Uri("files-uwp:?window="); + var filesUWPUri = new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable + $"?window="); return Launcher.LaunchUriAsync(filesUWPUri).AsTask(); } diff --git a/src/Files.App/MainWindow.xaml.cs b/src/Files.App/MainWindow.xaml.cs index b6bfcceb6f9d..3d3972c9127b 100644 --- a/src/Files.App/MainWindow.xaml.cs +++ b/src/Files.App/MainWindow.xaml.cs @@ -71,7 +71,7 @@ public async Task InitializeApplicationAsync(object activatedEventArgs) { case ILaunchActivatedEventArgs launchArgs: if (launchArgs.Arguments is not null && - (CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files.exe", StringComparison.OrdinalIgnoreCase) + (CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith(Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasVariable, StringComparison.OrdinalIgnoreCase) || CommandLineParser.SplitArguments(launchArgs.Arguments, true)[0].EndsWith($"files", StringComparison.OrdinalIgnoreCase))) { // WINUI3: When launching from commandline the argument is not ICommandLineActivatedEventArgs (#10370) @@ -101,7 +101,7 @@ public async Task InitializeApplicationAsync(object activatedEventArgs) break; case IProtocolActivatedEventArgs eventArgs: - if (eventArgs.Uri.AbsoluteUri == "files-uwp:") + if (eventArgs.Uri.AbsoluteUri == Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable) { rootFrame.Navigate(typeof(MainPage), null, new SuppressNavigationTransitionInfo()); diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index 69a4cb1e7993..daea5d9cf2b0 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -217,7 +217,7 @@ static bool ProcessPathPredicate(Process p) var cmdLaunchArgs = activatedArgs.Data is ILaunchActivatedEventArgs launchArgs && launchArgs.Arguments is not null && CommandLineParser.SplitArguments(launchArgs.Arguments, true).FirstOrDefault() is string arg0 && - (arg0.EndsWith($"files.exe", StringComparison.OrdinalIgnoreCase) || + (arg0.EndsWith(Constants.AutomatedWorkflowInjectionKeys.FilesExecutionAliasVariable, StringComparison.OrdinalIgnoreCase) || arg0.EndsWith($"files", StringComparison.OrdinalIgnoreCase)) ? launchArgs.Arguments : null; var cmdProtocolArgs = activatedArgs.Data is IProtocolActivatedEventArgs protocolArgs && protocolArgs.Uri.Query.TrimStart('?').Split('=') is string[] parsedArgs && diff --git a/src/Files.App/Utils/Taskbar/SystemTrayIcon.cs b/src/Files.App/Utils/Taskbar/SystemTrayIcon.cs index e94566279925..0f7f25a516a9 100644 --- a/src/Files.App/Utils/Taskbar/SystemTrayIcon.cs +++ b/src/Files.App/Utils/Taskbar/SystemTrayIcon.cs @@ -264,7 +264,7 @@ private void OnLeftClicked() { _lastLaunchDate = DateTime.Now; - _ = Launcher.LaunchUriAsync(new Uri("files-uwp:")); + _ = Launcher.LaunchUriAsync(new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable)); } else MainWindow.Instance.Activate(); diff --git a/src/Files.App/ViewModels/Settings/GeneralViewModel.cs b/src/Files.App/ViewModels/Settings/GeneralViewModel.cs index cfa12ba59c89..d475717b4d3f 100644 --- a/src/Files.App/ViewModels/Settings/GeneralViewModel.cs +++ b/src/Files.App/ViewModels/Settings/GeneralViewModel.cs @@ -121,7 +121,7 @@ private async void DoRestartAsync() AppLifecycleHelper.SaveSessionTabs(); // Launches a new instance of Files - await Launcher.LaunchUriAsync(new Uri("files-uwp:")); + await Launcher.LaunchUriAsync(new Uri(Constants.AutomatedWorkflowInjectionKeys.FilesUriSchemaVariable)); // Closes the current instance Process.GetCurrentProcess().Kill();