diff --git a/src/settings-ui/QuickAccess.UI/Helpers/ModuleHelper.cs b/src/settings-ui/QuickAccess.UI/Helpers/ModuleHelper.cs
new file mode 100644
index 0000000000..3e52133324
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/Helpers/ModuleHelper.cs
@@ -0,0 +1,155 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using global::PowerToys.GPOWrapper;
+using ManagedCommon;
+using Microsoft.PowerToys.Settings.UI.Library;
+
+namespace Microsoft.PowerToys.QuickAccess.Helpers;
+
+internal static class ModuleHelper
+{
+ public static string GetModuleLabelResourceName(ModuleType moduleType)
+ {
+ return moduleType switch
+ {
+ ModuleType.Workspaces => "Workspaces/ModuleTitle",
+ ModuleType.PowerAccent => "QuickAccent/ModuleTitle",
+ ModuleType.PowerOCR => "TextExtractor/ModuleTitle",
+ ModuleType.FindMyMouse => "MouseUtils_FindMyMouse/Header",
+ ModuleType.MouseHighlighter => "MouseUtils_MouseHighlighter/Header",
+ ModuleType.MouseJump => "MouseUtils_MouseJump/Header",
+ ModuleType.MousePointerCrosshairs => "MouseUtils_MousePointerCrosshairs/Header",
+ ModuleType.CursorWrap => "MouseUtils_CursorWrap/Header",
+ _ => $"{moduleType}/ModuleTitle",
+ };
+ }
+
+ public static string GetModuleTypeFluentIconName(ModuleType moduleType)
+ {
+ return moduleType switch
+ {
+ ModuleType.AdvancedPaste => "ms-appx:///Assets/Settings/Icons/AdvancedPaste.png",
+ ModuleType.Workspaces => "ms-appx:///Assets/Settings/Icons/Workspaces.png",
+ ModuleType.PowerOCR => "ms-appx:///Assets/Settings/Icons/TextExtractor.png",
+ ModuleType.PowerAccent => "ms-appx:///Assets/Settings/Icons/QuickAccent.png",
+ ModuleType.MousePointerCrosshairs => "ms-appx:///Assets/Settings/Icons/MouseCrosshairs.png",
+ ModuleType.MeasureTool => "ms-appx:///Assets/Settings/Icons/ScreenRuler.png",
+ ModuleType.PowerLauncher => "ms-appx:///Assets/Settings/Icons/PowerToysRun.png",
+ _ => $"ms-appx:///Assets/Settings/Icons/{moduleType}.png",
+ };
+ }
+
+ public static bool GetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType)
+ {
+ return moduleType switch
+ {
+ ModuleType.AdvancedPaste => generalSettingsConfig.Enabled.AdvancedPaste,
+ ModuleType.AlwaysOnTop => generalSettingsConfig.Enabled.AlwaysOnTop,
+ ModuleType.Awake => generalSettingsConfig.Enabled.Awake,
+ ModuleType.CmdPal => generalSettingsConfig.Enabled.CmdPal,
+ ModuleType.ColorPicker => generalSettingsConfig.Enabled.ColorPicker,
+ ModuleType.CropAndLock => generalSettingsConfig.Enabled.CropAndLock,
+ ModuleType.CursorWrap => generalSettingsConfig.Enabled.CursorWrap,
+ ModuleType.LightSwitch => generalSettingsConfig.Enabled.LightSwitch,
+ ModuleType.EnvironmentVariables => generalSettingsConfig.Enabled.EnvironmentVariables,
+ ModuleType.FancyZones => generalSettingsConfig.Enabled.FancyZones,
+ ModuleType.FileLocksmith => generalSettingsConfig.Enabled.FileLocksmith,
+ ModuleType.FindMyMouse => generalSettingsConfig.Enabled.FindMyMouse,
+ ModuleType.Hosts => generalSettingsConfig.Enabled.Hosts,
+ ModuleType.ImageResizer => generalSettingsConfig.Enabled.ImageResizer,
+ ModuleType.KeyboardManager => generalSettingsConfig.Enabled.KeyboardManager,
+ ModuleType.MouseHighlighter => generalSettingsConfig.Enabled.MouseHighlighter,
+ ModuleType.MouseJump => generalSettingsConfig.Enabled.MouseJump,
+ ModuleType.MousePointerCrosshairs => generalSettingsConfig.Enabled.MousePointerCrosshairs,
+ ModuleType.MouseWithoutBorders => generalSettingsConfig.Enabled.MouseWithoutBorders,
+ ModuleType.NewPlus => generalSettingsConfig.Enabled.NewPlus,
+ ModuleType.Peek => generalSettingsConfig.Enabled.Peek,
+ ModuleType.PowerRename => generalSettingsConfig.Enabled.PowerRename,
+ ModuleType.PowerLauncher => generalSettingsConfig.Enabled.PowerLauncher,
+ ModuleType.PowerAccent => generalSettingsConfig.Enabled.PowerAccent,
+ ModuleType.Workspaces => generalSettingsConfig.Enabled.Workspaces,
+ ModuleType.RegistryPreview => generalSettingsConfig.Enabled.RegistryPreview,
+ ModuleType.MeasureTool => generalSettingsConfig.Enabled.MeasureTool,
+ ModuleType.ShortcutGuide => generalSettingsConfig.Enabled.ShortcutGuide,
+ ModuleType.PowerOCR => generalSettingsConfig.Enabled.PowerOcr,
+ ModuleType.ZoomIt => generalSettingsConfig.Enabled.ZoomIt,
+ _ => false,
+ };
+ }
+
+ public static void SetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType, bool isEnabled)
+ {
+ switch (moduleType)
+ {
+ case ModuleType.AdvancedPaste: generalSettingsConfig.Enabled.AdvancedPaste = isEnabled; break;
+ case ModuleType.AlwaysOnTop: generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break;
+ case ModuleType.Awake: generalSettingsConfig.Enabled.Awake = isEnabled; break;
+ case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
+ case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
+ case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
+ case ModuleType.CursorWrap: generalSettingsConfig.Enabled.CursorWrap = isEnabled; break;
+ case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
+ case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
+ case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
+ case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
+ case ModuleType.FindMyMouse: generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break;
+ case ModuleType.Hosts: generalSettingsConfig.Enabled.Hosts = isEnabled; break;
+ case ModuleType.ImageResizer: generalSettingsConfig.Enabled.ImageResizer = isEnabled; break;
+ case ModuleType.KeyboardManager: generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break;
+ case ModuleType.MouseHighlighter: generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break;
+ case ModuleType.MouseJump: generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
+ case ModuleType.MousePointerCrosshairs: generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
+ case ModuleType.MouseWithoutBorders: generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
+ case ModuleType.NewPlus: generalSettingsConfig.Enabled.NewPlus = isEnabled; break;
+ case ModuleType.Peek: generalSettingsConfig.Enabled.Peek = isEnabled; break;
+ case ModuleType.PowerRename: generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
+ case ModuleType.PowerLauncher: generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
+ case ModuleType.PowerAccent: generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
+ case ModuleType.Workspaces: generalSettingsConfig.Enabled.Workspaces = isEnabled; break;
+ case ModuleType.RegistryPreview: generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
+ case ModuleType.MeasureTool: generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
+ case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
+ case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOcr = isEnabled; break;
+ case ModuleType.ZoomIt: generalSettingsConfig.Enabled.ZoomIt = isEnabled; break;
+ }
+ }
+
+ public static GpoRuleConfigured GetModuleGpoConfiguration(ModuleType moduleType)
+ {
+ return moduleType switch
+ {
+ ModuleType.AdvancedPaste => GPOWrapper.GetConfiguredAdvancedPasteEnabledValue(),
+ ModuleType.AlwaysOnTop => GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(),
+ ModuleType.Awake => GPOWrapper.GetConfiguredAwakeEnabledValue(),
+ ModuleType.CmdPal => GPOWrapper.GetConfiguredCmdPalEnabledValue(),
+ ModuleType.ColorPicker => GPOWrapper.GetConfiguredColorPickerEnabledValue(),
+ ModuleType.CropAndLock => GPOWrapper.GetConfiguredCropAndLockEnabledValue(),
+ ModuleType.CursorWrap => GPOWrapper.GetConfiguredCursorWrapEnabledValue(),
+ ModuleType.EnvironmentVariables => GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue(),
+ ModuleType.FancyZones => GPOWrapper.GetConfiguredFancyZonesEnabledValue(),
+ ModuleType.FileLocksmith => GPOWrapper.GetConfiguredFileLocksmithEnabledValue(),
+ ModuleType.FindMyMouse => GPOWrapper.GetConfiguredFindMyMouseEnabledValue(),
+ ModuleType.Hosts => GPOWrapper.GetConfiguredHostsFileEditorEnabledValue(),
+ ModuleType.ImageResizer => GPOWrapper.GetConfiguredImageResizerEnabledValue(),
+ ModuleType.KeyboardManager => GPOWrapper.GetConfiguredKeyboardManagerEnabledValue(),
+ ModuleType.MouseHighlighter => GPOWrapper.GetConfiguredMouseHighlighterEnabledValue(),
+ ModuleType.MouseJump => GPOWrapper.GetConfiguredMouseJumpEnabledValue(),
+ ModuleType.MousePointerCrosshairs => GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue(),
+ ModuleType.MouseWithoutBorders => GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue(),
+ ModuleType.NewPlus => GPOWrapper.GetConfiguredNewPlusEnabledValue(),
+ ModuleType.Peek => GPOWrapper.GetConfiguredPeekEnabledValue(),
+ ModuleType.PowerRename => GPOWrapper.GetConfiguredPowerRenameEnabledValue(),
+ ModuleType.PowerLauncher => GPOWrapper.GetConfiguredPowerLauncherEnabledValue(),
+ ModuleType.PowerAccent => GPOWrapper.GetConfiguredQuickAccentEnabledValue(),
+ ModuleType.Workspaces => GPOWrapper.GetConfiguredWorkspacesEnabledValue(),
+ ModuleType.RegistryPreview => GPOWrapper.GetConfiguredRegistryPreviewEnabledValue(),
+ ModuleType.MeasureTool => GPOWrapper.GetConfiguredScreenRulerEnabledValue(),
+ ModuleType.ShortcutGuide => GPOWrapper.GetConfiguredShortcutGuideEnabledValue(),
+ ModuleType.PowerOCR => GPOWrapper.GetConfiguredTextExtractorEnabledValue(),
+ ModuleType.ZoomIt => GPOWrapper.GetConfiguredZoomItEnabledValue(),
+ _ => GpoRuleConfigured.Unavailable,
+ };
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/Helpers/ResourceLoaderInstance.cs b/src/settings-ui/QuickAccess.UI/Helpers/ResourceLoaderInstance.cs
new file mode 100644
index 0000000000..b57d73015b
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/Helpers/ResourceLoaderInstance.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Windows.ApplicationModel.Resources;
+
+namespace Microsoft.PowerToys.QuickAccess.Helpers;
+
+internal static class ResourceLoaderInstance
+{
+ internal static ResourceLoader ResourceLoader { get; } = new("PowerToys.QuickAccess.pri");
+}
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml
new file mode 100644
index 0000000000..f2a0ece8d5
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs
new file mode 100644
index 0000000000..0834e836ec
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.PowerToys.QuickAccess.ViewModels;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media.Animation;
+using Microsoft.UI.Xaml.Navigation;
+
+namespace Microsoft.PowerToys.QuickAccess.Flyout;
+
+public sealed partial class AppsListPage : Page
+{
+ private FlyoutNavigationContext? _context;
+
+ public AppsListPage()
+ {
+ InitializeComponent();
+ }
+
+ public AllAppsViewModel ViewModel { get; private set; } = default!;
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+
+ if (e.Parameter is FlyoutNavigationContext context)
+ {
+ _context = context;
+ ViewModel = context.AllAppsViewModel;
+ DataContext = ViewModel;
+ }
+ }
+
+ private void BackButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (_context == null || Frame == null)
+ {
+ return;
+ }
+
+ Frame.Navigate(typeof(LaunchPage), _context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft });
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs
new file mode 100644
index 0000000000..3aab3ca334
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.PowerToys.QuickAccess.Services;
+using Microsoft.PowerToys.QuickAccess.ViewModels;
+
+namespace Microsoft.PowerToys.QuickAccess.Flyout;
+
+internal sealed record FlyoutNavigationContext(
+ LauncherViewModel LauncherViewModel,
+ AllAppsViewModel AllAppsViewModel,
+ IQuickAccessCoordinator Coordinator);
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml
new file mode 100644
index 0000000000..073558245c
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml.cs
new file mode 100644
index 0000000000..5aea293cca
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml.cs
@@ -0,0 +1,201 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using ManagedCommon;
+using Microsoft.PowerToys.QuickAccess.Services;
+using Microsoft.PowerToys.QuickAccess.ViewModels;
+using Microsoft.PowerToys.Settings.UI.Controls;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media.Animation;
+using Microsoft.UI.Xaml.Navigation;
+using PowerToys.Interop;
+using Windows.System;
+
+namespace Microsoft.PowerToys.QuickAccess.Flyout;
+
+public sealed partial class LaunchPage : Page
+{
+ private AllAppsViewModel? _allAppsViewModel;
+ private IQuickAccessCoordinator? _coordinator;
+
+ public LaunchPage()
+ {
+ InitializeComponent();
+ }
+
+ public LauncherViewModel ViewModel { get; private set; } = default!;
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+
+ if (e.Parameter is FlyoutNavigationContext context)
+ {
+ ViewModel = context.LauncherViewModel;
+ _allAppsViewModel = context.AllAppsViewModel;
+ _coordinator = context.Coordinator;
+ DataContext = ViewModel;
+ }
+ }
+
+ private void ModuleButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (sender is not FlyoutMenuButton selectedModuleBtn)
+ {
+ return;
+ }
+
+ if (selectedModuleBtn.Tag is not ModuleType moduleType)
+ {
+ return;
+ }
+
+ bool moduleRun = true;
+
+ switch (moduleType)
+ {
+ case ModuleType.ColorPicker:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.EnvironmentVariables:
+ {
+ bool launchAdmin = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
+ bool isElevated = _coordinator?.IsRunnerElevated ?? false;
+ string eventName = !isElevated && launchAdmin
+ ? Constants.ShowEnvironmentVariablesAdminSharedEvent()
+ : Constants.ShowEnvironmentVariablesSharedEvent();
+
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
+ {
+ eventHandle.Set();
+ }
+ }
+
+ break;
+ case ModuleType.FancyZones:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.Hosts:
+ {
+ bool launchAdmin = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
+ bool isElevated = _coordinator?.IsRunnerElevated ?? false;
+ string eventName = !isElevated && launchAdmin
+ ? Constants.ShowHostsAdminSharedEvent()
+ : Constants.ShowHostsSharedEvent();
+
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
+ {
+ eventHandle.Set();
+ }
+ }
+
+ break;
+ case ModuleType.PowerLauncher:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.PowerOCR:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.RegistryPreview:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.MeasureTool:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.ShortcutGuide:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.CmdPal:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowCmdPalEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ case ModuleType.Workspaces:
+ using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.WorkspacesLaunchEditorEvent()))
+ {
+ eventHandle.Set();
+ }
+
+ break;
+ default:
+ moduleRun = false;
+ break;
+ }
+
+ if (moduleRun)
+ {
+ _coordinator?.OnModuleLaunched(moduleType);
+ }
+
+ _coordinator?.HideFlyout();
+ }
+
+ private void SettingsBtn_Click(object sender, RoutedEventArgs e)
+ {
+ _coordinator?.OpenSettings();
+ }
+
+ private async void DocsBtn_Click(object sender, RoutedEventArgs e)
+ {
+ if (_coordinator == null || !await _coordinator.ShowDocumentationAsync())
+ {
+ await Launcher.LaunchUriAsync(new Uri("https://aka.ms/PowerToysOverview"));
+ }
+ }
+
+ private void AllAppButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (Frame == null || _allAppsViewModel == null || ViewModel == null || _coordinator == null)
+ {
+ return;
+ }
+
+ var context = new FlyoutNavigationContext(ViewModel, _allAppsViewModel, _coordinator);
+ Frame.Navigate(typeof(AppsListPage), context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromRight });
+ }
+
+ private void ReportBugBtn_Click(object sender, RoutedEventArgs e)
+ {
+ }
+
+ private void UpdateInfoBar_Tapped(object sender, TappedRoutedEventArgs e)
+ {
+ _coordinator?.OpenGeneralSettingsForUpdates();
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml
new file mode 100644
index 0000000000..5f19844d69
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml.cs
new file mode 100644
index 0000000000..e5b4d23cb5
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/ShellPage.xaml.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.PowerToys.QuickAccess.Services;
+using Microsoft.PowerToys.QuickAccess.ViewModels;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media.Animation;
+
+namespace Microsoft.PowerToys.QuickAccess.Flyout;
+
+///
+/// Hosts the flyout navigation frame.
+///
+public sealed partial class ShellPage : Page
+{
+ private LauncherViewModel? _launcherViewModel;
+ private AllAppsViewModel? _allAppsViewModel;
+ private IQuickAccessCoordinator? _coordinator;
+
+ public ShellPage()
+ {
+ InitializeComponent();
+ }
+
+ public void Initialize(IQuickAccessCoordinator coordinator, LauncherViewModel launcherViewModel, AllAppsViewModel allAppsViewModel)
+ {
+ _coordinator = coordinator;
+ _launcherViewModel = launcherViewModel;
+ _allAppsViewModel = allAppsViewModel;
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (_launcherViewModel == null || _allAppsViewModel == null || _coordinator == null)
+ {
+ return;
+ }
+
+ if (ContentFrame.Content is LaunchPage)
+ {
+ return;
+ }
+
+ var context = new FlyoutNavigationContext(_launcherViewModel, _allAppsViewModel, _coordinator);
+ ContentFrame.Navigate(typeof(LaunchPage), context, new SuppressNavigationTransitionInfo());
+ }
+
+ internal void NavigateToLaunch()
+ {
+ if (_launcherViewModel == null || _allAppsViewModel == null || _coordinator == null)
+ {
+ return;
+ }
+
+ var context = new FlyoutNavigationContext(_launcherViewModel, _allAppsViewModel, _coordinator);
+ ContentFrame.Navigate(typeof(LaunchPage), context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft });
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/Services/IQuickAccessCoordinator.cs b/src/settings-ui/QuickAccess.UI/Services/IQuickAccessCoordinator.cs
new file mode 100644
index 0000000000..e739f03b42
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/Services/IQuickAccessCoordinator.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using ManagedCommon;
+
+namespace Microsoft.PowerToys.QuickAccess.Services;
+
+public interface IQuickAccessCoordinator
+{
+ bool IsRunnerElevated { get; }
+
+ void HideFlyout();
+
+ void OpenSettings();
+
+ void OpenGeneralSettingsForUpdates();
+
+ Task ShowDocumentationAsync();
+
+ void NotifyUserSettingsInteraction();
+
+ bool UpdateModuleEnabled(ModuleType moduleType, bool isEnabled);
+
+ void OnModuleLaunched(ModuleType moduleType);
+}
diff --git a/src/settings-ui/QuickAccess.UI/Services/QuickAccessCoordinator.cs b/src/settings-ui/QuickAccess.UI/Services/QuickAccessCoordinator.cs
new file mode 100644
index 0000000000..c0be5252d1
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/Services/QuickAccessCoordinator.cs
@@ -0,0 +1,186 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading.Tasks;
+using Common.UI;
+using ManagedCommon;
+using Microsoft.PowerToys.QuickAccess.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Helpers;
+using PowerToys.Interop;
+
+namespace Microsoft.PowerToys.QuickAccess.Services;
+
+internal sealed class QuickAccessCoordinator : IQuickAccessCoordinator, IDisposable
+{
+ private readonly MainWindow _window;
+ private readonly QuickAccessLaunchContext _launchContext;
+ private readonly SettingsUtils _settingsUtils = new();
+ private readonly object _generalSettingsLock = new();
+ private readonly object _ipcLock = new();
+ private TwoWayPipeMessageIPCManaged? _ipcManager;
+ private bool _ipcUnavailableLogged;
+
+ public QuickAccessCoordinator(MainWindow window, QuickAccessLaunchContext launchContext)
+ {
+ _window = window;
+ _launchContext = launchContext;
+ InitializeIpc();
+ }
+
+ public bool IsRunnerElevated => false; // TODO: wire up real elevation state.
+
+ public void HideFlyout()
+ {
+ _window.RequestHide();
+ }
+
+ public void OpenSettings()
+ {
+ SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.Dashboard, true);
+ _window.RequestHide();
+ }
+
+ public void OpenGeneralSettingsForUpdates()
+ {
+ SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.Overview, true);
+ _window.RequestHide();
+ }
+
+ public Task ShowDocumentationAsync()
+ {
+ Logger.LogInfo("QuickAccessCoordinator.ShowDocumentationAsync is not yet connected.");
+ return Task.FromResult(false);
+ }
+
+ public void NotifyUserSettingsInteraction()
+ {
+ Logger.LogDebug("QuickAccessCoordinator.NotifyUserSettingsInteraction invoked.");
+ }
+
+ public bool UpdateModuleEnabled(ModuleType moduleType, bool isEnabled)
+ {
+ GeneralSettings? updatedSettings = null;
+ lock (_generalSettingsLock)
+ {
+ var repository = SettingsRepository.GetInstance(_settingsUtils);
+ var generalSettings = repository.SettingsConfig;
+ var current = ModuleHelper.GetIsModuleEnabled(generalSettings, moduleType);
+ if (current == isEnabled)
+ {
+ return false;
+ }
+
+ ModuleHelper.SetIsModuleEnabled(generalSettings, moduleType, isEnabled);
+ _settingsUtils.SaveSettings(generalSettings.ToJsonString());
+ Logger.LogInfo($"QuickAccess updated module '{moduleType}' enabled state to {isEnabled}.");
+ updatedSettings = generalSettings;
+ }
+
+ if (updatedSettings != null)
+ {
+ SendGeneralSettingsUpdate(updatedSettings);
+ }
+
+ return true;
+ }
+
+ public void OnModuleLaunched(ModuleType moduleType)
+ {
+ Logger.LogInfo($"QuickAccessLauncher invoked module {moduleType}.");
+ }
+
+ public void Dispose()
+ {
+ DisposeIpc();
+ }
+
+ private void InitializeIpc()
+ {
+ if (string.IsNullOrEmpty(_launchContext.RunnerPipeName) || string.IsNullOrEmpty(_launchContext.AppPipeName))
+ {
+ Logger.LogWarning("QuickAccessCoordinator: IPC pipe names not provided. Runner will not receive updates.");
+ return;
+ }
+
+ try
+ {
+ _ipcManager = new TwoWayPipeMessageIPCManaged(_launchContext.AppPipeName, _launchContext.RunnerPipeName, OnIpcMessageReceived);
+ _ipcManager.Start();
+ _ipcUnavailableLogged = false;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("QuickAccessCoordinator: failed to start IPC channel to runner.", ex);
+ DisposeIpc();
+ }
+ }
+
+ private void OnIpcMessageReceived(string message)
+ {
+ Logger.LogDebug($"QuickAccessCoordinator received IPC payload: {message}");
+ }
+
+ private void SendGeneralSettingsUpdate(GeneralSettings updatedSettings)
+ {
+ string payload;
+ try
+ {
+ payload = new OutGoingGeneralSettings(updatedSettings).ToString();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("QuickAccessCoordinator: failed to serialize general settings payload.", ex);
+ return;
+ }
+
+ lock (_ipcLock)
+ {
+ if (_ipcManager == null)
+ {
+ if (!_ipcUnavailableLogged)
+ {
+ _ipcUnavailableLogged = true;
+ Logger.LogWarning("QuickAccessCoordinator: unable to send settings update because IPC is not available.");
+ }
+
+ return;
+ }
+
+ try
+ {
+ _ipcManager.Send(payload);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("QuickAccessCoordinator: failed to send general settings update to runner.", ex);
+ }
+ }
+ }
+
+ private void DisposeIpc()
+ {
+ lock (_ipcLock)
+ {
+ if (_ipcManager == null)
+ {
+ return;
+ }
+
+ try
+ {
+ _ipcManager.End();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogWarning($"QuickAccessCoordinator: exception while shutting down IPC. {ex.Message}");
+ }
+
+ _ipcManager.Dispose();
+ _ipcManager = null;
+ _ipcUnavailableLogged = false;
+ }
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/ViewModels/AllAppsViewModel.cs b/src/settings-ui/QuickAccess.UI/ViewModels/AllAppsViewModel.cs
new file mode 100644
index 0000000000..7db99a50e7
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/ViewModels/AllAppsViewModel.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.ObjectModel;
+using global::PowerToys.GPOWrapper;
+using ManagedCommon;
+using Microsoft.PowerToys.QuickAccess.Helpers;
+using Microsoft.PowerToys.QuickAccess.Services;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
+using Microsoft.Windows.ApplicationModel.Resources;
+
+namespace Microsoft.PowerToys.QuickAccess.ViewModels;
+
+public sealed class AllAppsViewModel : Observable
+{
+ private readonly IQuickAccessCoordinator _coordinator;
+ private readonly ISettingsRepository _settingsRepository;
+ private readonly ResourceLoader _resourceLoader;
+ private GeneralSettings _generalSettings;
+
+ public ObservableCollection FlyoutMenuItems { get; }
+
+ public AllAppsViewModel(IQuickAccessCoordinator coordinator)
+ {
+ _coordinator = coordinator;
+ var settingsUtils = new SettingsUtils();
+ _settingsRepository = SettingsRepository.GetInstance(settingsUtils);
+ _generalSettings = _settingsRepository.SettingsConfig;
+ _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
+
+ _resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
+ FlyoutMenuItems = new ObservableCollection();
+
+ foreach (ModuleType moduleType in Enum.GetValues())
+ {
+ AddFlyoutMenuItem(moduleType);
+ }
+ }
+
+ private void AddFlyoutMenuItem(ModuleType moduleType)
+ {
+ var gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
+ var isLocked = gpo is GpoRuleConfigured.Enabled or GpoRuleConfigured.Disabled;
+ var isEnabled = gpo == GpoRuleConfigured.Enabled || (!isLocked && ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType));
+
+ FlyoutMenuItems.Add(new FlyoutMenuItem
+ {
+ Label = _resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
+ IsEnabled = isEnabled,
+ IsLocked = isLocked,
+ Tag = moduleType,
+ Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
+ EnabledChangedCallback = EnabledChangedOnUI,
+ });
+ }
+
+ private void EnabledChangedOnUI(FlyoutMenuItem item)
+ {
+ if (_coordinator.UpdateModuleEnabled(item.Tag, item.IsEnabled))
+ {
+ _coordinator.NotifyUserSettingsInteraction();
+ }
+ }
+
+ private void ModuleEnabledChangedOnSettingsPage()
+ {
+ _generalSettings = _settingsRepository.SettingsConfig;
+ _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
+
+ foreach (var item in FlyoutMenuItems)
+ {
+ if (!item.IsLocked)
+ {
+ item.IsEnabled = ModuleHelper.GetIsModuleEnabled(_generalSettings, item.Tag);
+ }
+ }
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/ViewModels/FlyoutMenuItem.cs b/src/settings-ui/QuickAccess.UI/ViewModels/FlyoutMenuItem.cs
new file mode 100644
index 0000000000..91de44f137
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/ViewModels/FlyoutMenuItem.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using ManagedCommon;
+
+namespace Microsoft.PowerToys.QuickAccess.ViewModels;
+
+public sealed class FlyoutMenuItem : INotifyPropertyChanged
+{
+ private bool _visible;
+ private bool _isEnabled;
+
+ public string Label { get; set; } = string.Empty;
+
+ public string Icon { get; set; } = string.Empty;
+
+ public string ToolTip { get; set; } = string.Empty;
+
+ public ModuleType Tag { get; set; }
+
+ public bool IsLocked { get; set; }
+
+ public bool IsEnabled
+ {
+ get => _isEnabled;
+ set
+ {
+ if (_isEnabled != value)
+ {
+ _isEnabled = value;
+ OnPropertyChanged();
+ EnabledChangedCallback?.Invoke(this);
+ }
+ }
+ }
+
+ public Action? EnabledChangedCallback { get; set; }
+
+ public bool Visible
+ {
+ get => _visible;
+ set
+ {
+ if (_visible != value)
+ {
+ _visible = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
diff --git a/src/settings-ui/QuickAccess.UI/ViewModels/LauncherViewModel.cs b/src/settings-ui/QuickAccess.UI/ViewModels/LauncherViewModel.cs
new file mode 100644
index 0000000000..8d34312c3d
--- /dev/null
+++ b/src/settings-ui/QuickAccess.UI/ViewModels/LauncherViewModel.cs
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.ObjectModel;
+using global::PowerToys.GPOWrapper;
+using ManagedCommon;
+using Microsoft.PowerToys.QuickAccess.Helpers;
+using Microsoft.PowerToys.QuickAccess.Services;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
+using Microsoft.Windows.ApplicationModel.Resources;
+
+namespace Microsoft.PowerToys.QuickAccess.ViewModels;
+
+public sealed class LauncherViewModel : Observable
+{
+ private readonly IQuickAccessCoordinator _coordinator;
+ private readonly ISettingsRepository _settingsRepository;
+ private readonly ResourceLoader _resourceLoader;
+ private GeneralSettings _generalSettings;
+
+ public ObservableCollection FlyoutMenuItems { get; }
+
+ public bool IsUpdateAvailable { get; private set; }
+
+ public LauncherViewModel(IQuickAccessCoordinator coordinator)
+ {
+ _coordinator = coordinator;
+ var settingsUtils = new SettingsUtils();
+ _settingsRepository = SettingsRepository.GetInstance(settingsUtils);
+ _generalSettings = _settingsRepository.SettingsConfig;
+ _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
+
+ _resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
+ FlyoutMenuItems = new ObservableCollection();
+
+ AddFlyoutMenuItem(ModuleType.ColorPicker);
+ AddFlyoutMenuItem(ModuleType.CmdPal);
+ AddFlyoutMenuItem(ModuleType.EnvironmentVariables);
+ AddFlyoutMenuItem(ModuleType.FancyZones);
+ AddFlyoutMenuItem(ModuleType.Hosts);
+ AddFlyoutMenuItem(ModuleType.PowerLauncher);
+ AddFlyoutMenuItem(ModuleType.PowerOCR);
+ AddFlyoutMenuItem(ModuleType.RegistryPreview);
+ AddFlyoutMenuItem(ModuleType.MeasureTool);
+ AddFlyoutMenuItem(ModuleType.ShortcutGuide);
+ AddFlyoutMenuItem(ModuleType.Workspaces);
+
+ var updatingSettings = UpdatingSettings.LoadSettings() ?? new UpdatingSettings();
+ IsUpdateAvailable = updatingSettings.State is UpdatingSettings.UpdatingState.ReadyToInstall or UpdatingSettings.UpdatingState.ReadyToDownload;
+ }
+
+ private void AddFlyoutMenuItem(ModuleType moduleType)
+ {
+ if (ModuleHelper.GetModuleGpoConfiguration(moduleType) == GpoRuleConfigured.Disabled)
+ {
+ return;
+ }
+
+ FlyoutMenuItems.Add(new FlyoutMenuItem
+ {
+ Label = _resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
+ Tag = moduleType,
+ Visible = ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType),
+ ToolTip = GetModuleToolTip(moduleType),
+ Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
+ });
+ }
+
+ private string GetModuleToolTip(ModuleType moduleType)
+ {
+ return moduleType switch
+ {
+ ModuleType.ColorPicker => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
+ ModuleType.FancyZones => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.ToString(),
+ ModuleType.PowerLauncher => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.ToString(),
+ ModuleType.PowerOCR => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
+ ModuleType.Workspaces => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.Hotkey.Value.ToString(),
+ ModuleType.MeasureTool => SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
+ ModuleType.ShortcutGuide => GetShortcutGuideToolTip(),
+ _ => string.Empty,
+ };
+ }
+
+ private string GetShortcutGuideToolTip()
+ {
+ var shortcutGuideSettings = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig;
+ return shortcutGuideSettings.Properties.UseLegacyPressWinKeyBehavior.Value
+ ? "Win"
+ : shortcutGuideSettings.Properties.OpenShortcutGuide.ToString();
+ }
+
+ private void ModuleEnabledChanged()
+ {
+ _generalSettings = _settingsRepository.SettingsConfig;
+ _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
+ foreach (var item in FlyoutMenuItems)
+ {
+ item.Visible = ModuleHelper.GetIsModuleEnabled(_generalSettings, item.Tag);
+ }
+ }
+}