diff --git a/.github/actions/spell-check/excludes.txt b/.github/actions/spell-check/excludes.txt index 1c42d9e4a9..eb343d3775 100644 --- a/.github/actions/spell-check/excludes.txt +++ b/.github/actions/spell-check/excludes.txt @@ -79,6 +79,7 @@ ^\Q.pipelines/ESRPSigning_core.json\E$ ^\Qsrc/modules/colorPicker/ColorPickerUI/Shaders/GridShader.cso\E$ ^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$ +^\Qinstaller/PowerToysSetup/Settings.wxs\E$ ^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json\E$ ^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.18.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.19.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index d09e6d483e..bfbba4b263 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -201,6 +201,7 @@ CHILDACTIVATE CHILDWINDOW Choibalsan chrdavis +chromaticities Chrzan cht Chukotka @@ -848,6 +849,7 @@ Khakassia Khanty Khovd KILLFOCUS +killrunner Kitts Knownfolders Krai @@ -1446,6 +1448,7 @@ reencoded REFCLSID REFGUID REFIID +Refreshable REGCLS regedit regfile diff --git a/installer/PowerToysSetup/Settings.wxs b/installer/PowerToysSetup/Settings.wxs index c476277736..a1072b59f6 100644 --- a/installer/PowerToysSetup/Settings.wxs +++ b/installer/PowerToysSetup/Settings.wxs @@ -4,7 +4,7 @@ - + diff --git a/src/common/interop/interop.cpp b/src/common/interop/interop.cpp index 7d5bfe099f..a7ec3b47dd 100644 --- a/src/common/interop/interop.cpp +++ b/src/common/interop/interop.cpp @@ -187,6 +187,10 @@ public return gcnew String(CommonSharedConstants::FZE_EXIT_EVENT); } + static String ^ FZEToggleEvent() { + return gcnew String(CommonSharedConstants::FANCY_ZONES_EDITOR_TOGGLE_EVENT); + } + static String ^ ColorPickerSendSettingsTelemetryEvent() { return gcnew String(CommonSharedConstants::COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT); } @@ -207,6 +211,14 @@ public return gcnew String(CommonSharedConstants::POWERACCENT_EXIT_EVENT); } + static String ^ ShortcutGuideTriggerEvent() { + return gcnew String(CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT); + } + + static String + ^ MeasureToolTriggerEvent() { + return gcnew String(CommonSharedConstants::MEASURE_TOOL_TRIGGER_EVENT); + } static String ^ GcodePreviewResizeEvent() { return gcnew String(CommonSharedConstants::GCODE_PREVIEW_RESIZE_EVENT); } diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h index a1116a6065..512e5f3039 100644 --- a/src/common/interop/shared_constants.h +++ b/src/common/interop/shared_constants.h @@ -28,6 +28,8 @@ namespace CommonSharedConstants // Path to the event used to show Color Picker const wchar_t SHOW_COLOR_PICKER_SHARED_EVENT[] = L"Local\\ShowColorPickerEvent-8c46be2a-3e05-4186-b56b-4ae986ef2525"; + const wchar_t SHORTCUT_GUIDE_TRIGGER_EVENT[] = L"Local\\ShortcutGuide-TriggerEvent-d4275ad3-2531-4d19-9252-c0becbd9b496"; + const wchar_t SHORTCUT_GUIDE_EXIT_EVENT[] = L"Local\\ShortcutGuide-ExitEvent-35697cdd-a3d2-47d6-a246-34efcc73eac0"; const wchar_t FANCY_ZONES_EDITOR_TOGGLE_EVENT[] = L"Local\\FancyZones-ToggleEditorEvent-1e174338-06a3-472b-874d-073b21c62f14"; @@ -44,6 +46,9 @@ namespace CommonSharedConstants // Path to the event used by PowerOCR const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a"; + // Path to the event used by MeasureTool + const wchar_t MEASURE_TOOL_TRIGGER_EVENT[] = L"Local\\MeasureToolEvent-3d46745f-09b3-4671-a577-236be7abd199"; + // Path to the event used by GcodePreviewHandler const wchar_t GCODE_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysGcodePreviewResizeEvent-6ff1f9bd-ccbd-4b24-a79f-40a34fb0317d"; diff --git a/src/modules/MeasureTool/MeasureToolModuleInterface/dllmain.cpp b/src/modules/MeasureTool/MeasureToolModuleInterface/dllmain.cpp index ac80a4a399..4148effdb1 100644 --- a/src/modules/MeasureTool/MeasureToolModuleInterface/dllmain.cpp +++ b/src/modules/MeasureTool/MeasureToolModuleInterface/dllmain.cpp @@ -3,9 +3,11 @@ #include #include #include "trace.h" +#include #include #include #include +#include extern "C" IMAGE_DOS_HEADER __ImageBase; @@ -49,6 +51,9 @@ private: Hotkey m_hotkey; HANDLE m_hProcess; + HANDLE triggerEvent; + EventWaiter triggerEventWaiter; + void parse_hotkey(PowerToysSettings::PowerToyValues& settings) { auto settingsObject = settings.get_raw_json(); @@ -142,6 +147,11 @@ public: { LoggerHelpers::init_logger(L"Measure Tool", L"ModuleInterface", "Measure Tool"); init_settings(); + + triggerEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::MEASURE_TOOL_TRIGGER_EVENT); + triggerEventWaiter = EventWaiter(CommonSharedConstants::MEASURE_TOOL_TRIGGER_EVENT, [this](int) { + on_hotkey(0); + }); } ~MeasureTool() diff --git a/src/modules/MeasureTool/MeasureToolUI/MainWindow.xaml b/src/modules/MeasureTool/MeasureToolUI/MainWindow.xaml index d787abb492..973781a777 100644 --- a/src/modules/MeasureTool/MeasureToolUI/MainWindow.xaml +++ b/src/modules/MeasureTool/MeasureToolUI/MainWindow.xaml @@ -5,8 +5,8 @@ xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)" xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:p="using:PowerToys.MeasureToolUI.Properties" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:p="using:PowerToys.MeasureToolUI.Properties" xmlns:winuiex="using:WinUIEx" IsAlwaysOnTop="True" IsMaximizable="False" diff --git a/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp b/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp index a7d7a1cc1b..de6c3a77ea 100644 --- a/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp +++ b/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp @@ -10,6 +10,7 @@ #include "../interface/powertoy_module_interface.h" #include "Generated Files/resource.h" #include +#include BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD /*ul_reason_for_call*/, LPVOID /*lpReserved*/) { @@ -35,6 +36,11 @@ public: Logger::warn(L"Failed to create {} event. {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT, get_last_error_or_default(GetLastError())); } + triggerEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT); + triggerEventWaiter = EventWaiter(CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT, [this](int) { + OnHotkeyEx(); + }); + InitSettings(); } @@ -191,7 +197,9 @@ private: UINT m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS; UINT m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS; + HANDLE triggerEvent; HANDLE exitEvent; + EventWaiter triggerEventWaiter; bool StartProcess(std::wstring args = L"") { diff --git a/src/runner/main.cpp b/src/runner/main.cpp index a5493afced..442eab5698 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -203,7 +203,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow { window = winrt::to_hstring(settingsWindow); } - open_settings_window(window); + open_settings_window(window, false); } if (openOobe) diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp index 340c6f5a70..53cae3bac3 100644 --- a/src/runner/settings_window.cpp +++ b/src/runner/settings_window.cpp @@ -11,12 +11,14 @@ #include "restart_elevated.h" #include "UpdateUtils.h" #include "centralized_kb_hook.h" +#include "Generated files/resource.h" #include #include #include #include #include +#include #include #include #include @@ -175,7 +177,7 @@ void dispatch_received_json(const std::wstring& json_to_parse) const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; { std::unique_lock lock{ ipc_mutex }; - if(current_settings_ipc) + if (current_settings_ipc) current_settings_ipc->send(settings_string); } } @@ -185,7 +187,7 @@ void dispatch_received_json(const std::wstring& json_to_parse) const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; { std::unique_lock lock{ ipc_mutex }; - if(current_settings_ipc) + if (current_settings_ipc) current_settings_ipc->send(settings_string); } } @@ -194,7 +196,7 @@ void dispatch_received_json(const std::wstring& json_to_parse) const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; { std::unique_lock lock{ ipc_mutex }; - if(current_settings_ipc) + if (current_settings_ipc) current_settings_ipc->send(settings_string); } } @@ -205,11 +207,35 @@ void dispatch_received_json(const std::wstring& json_to_parse) { { std::unique_lock lock{ ipc_mutex }; - if(current_settings_ipc) + if (current_settings_ipc) current_settings_ipc->send(result.value()); } } } + else if (name == L"bugreport") + { + std::wstring bug_report_path = get_module_folderpath(); + bug_report_path += L"\\Tools\\PowerToys.BugReportTool.exe"; + SHELLEXECUTEINFOW sei{ sizeof(sei) }; + sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE }; + sei.lpFile = bug_report_path.c_str(); + sei.nShow = SW_HIDE; + if (ShellExecuteExW(&sei)) + { + WaitForSingleObject(sei.hProcess, INFINITE); + CloseHandle(sei.hProcess); + static const std::wstring bugreport_success = GET_RESOURCE_STRING(IDS_BUGREPORT_SUCCESS); + MessageBoxW(nullptr, bugreport_success.c_str(), L"PowerToys", MB_OK); + } + } + else if (name == L"killrunner") + { + const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr); + if (pt_main_window != nullptr) + { + SendMessageW(pt_main_window, WM_CLOSE, 0, 0); + } + } } return; } @@ -290,7 +316,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, DWORD g_settings_process_id = 0; -void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional settings_window) +void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional settings_window, bool show_flyout = false) { g_isLaunchInProgress = true; @@ -360,11 +386,14 @@ void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::op // Arg 9: should scoobe window be shown std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false"; + // Arg 10: should flyout be shown + std::wstring settings_showFlyout = show_flyout ? L"true" : L"false"; + // create general settings file to initialize the settings file with installation configurations like : // 1. Run on start up. PTSettingsHelper::save_general_settings(save_settings.to_json()); - std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {}", + std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {}", executable_path, powertoys_pipe_name, settings_pipe_name, @@ -373,7 +402,8 @@ void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::op settings_elevatedStatus, settings_isUserAnAdmin, settings_showOobe, - settings_showScoobe); + settings_showScoobe, + settings_showFlyout); if (settings_window.has_value()) { @@ -520,18 +550,33 @@ void bring_settings_to_front() EnumWindows(callback, 0); } -void open_settings_window(std::optional settings_window) +void open_settings_window(std::optional settings_window, bool show_flyout = false) { if (g_settings_process_id != 0) { - bring_settings_to_front(); + if (show_flyout) + { + if (current_settings_ipc) + { + current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}"); + } + } + else + { + // nl instead of showing the window, send message to it (flyout might need to be hidden, main setting window activated) + // bring_settings_to_front(); + if (current_settings_ipc) + { + current_settings_ipc->send(L"{\"ShowYourself\":\"main_page\"}"); + } + } } else { if (!g_isLaunchInProgress) { - std::thread([settings_window]() { - run_settings_window(false, false, settings_window); + std::thread([settings_window, show_flyout]() { + run_settings_window(false, false, settings_window, show_flyout); }).detach(); } } @@ -563,6 +608,13 @@ void open_scoobe_window() }).detach(); } +void open_flyout() +{ + std::thread([]() { + run_settings_window(false, false, std::nullopt, true); + }).detach(); +} + std::string ESettingsWindowNames_to_string(ESettingsWindowNames value) { switch (value) diff --git a/src/runner/settings_window.h b/src/runner/settings_window.h index 7e2f9ed89d..fcbb51b310 100644 --- a/src/runner/settings_window.h +++ b/src/runner/settings_window.h @@ -22,8 +22,9 @@ enum class ESettingsWindowNames std::string ESettingsWindowNames_to_string(ESettingsWindowNames value); ESettingsWindowNames ESettingsWindowNames_from_string(std::string value); -void open_settings_window(std::optional settings_window); +void open_settings_window(std::optional settings_window, bool show_flyout); void close_settings_window(); void open_oobe_window(); void open_scoobe_window(); +void open_flyout(); diff --git a/src/runner/tray_icon.cpp b/src/runner/tray_icon.cpp index 6fe32df61f..1ece986df7 100644 --- a/src/runner/tray_icon.cpp +++ b/src/runner/tray_icon.cpp @@ -30,6 +30,8 @@ namespace HMENU h_menu = nullptr; HMENU h_sub_menu = nullptr; + bool double_click_timer_running = false; + bool double_clicked = false; } // Struct to fill with callback and the data. The window_proc is responsible for cleaning it. @@ -69,7 +71,7 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam) case ID_SETTINGS_MENU_COMMAND: { std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast(lparam))) }; - open_settings_window(settings_window); + open_settings_window(settings_window, false); } break; case ID_EXIT_MENU_COMMAND: @@ -116,6 +118,15 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam) } } +void click_timer_elapsed() +{ + double_click_timer_running = false; + if (!double_clicked) + { + open_settings_window(std::nullopt, true); + } +} + LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { switch (message) @@ -168,11 +179,6 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam { switch (lparam) { - case WM_LBUTTONDBLCLK: - { - open_settings_window(std::nullopt); - break; - } case WM_RBUTTONUP: case WM_CONTEXTMENU: { @@ -186,7 +192,6 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam static std::wstring exit_menuitem_label = GET_RESOURCE_STRING(IDS_EXIT_MENU_TEXT); static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT); static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT); - change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data()); change_menu_item_text(ID_EXIT_MENU_COMMAND, exit_menuitem_label.data()); change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data()); @@ -200,6 +205,30 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam GetCursorPos(&mouse_pointer); SetForegroundWindow(window); // Needed for the context menu to disappear. TrackPopupMenu(h_sub_menu, TPM_CENTERALIGN | TPM_BOTTOMALIGN, mouse_pointer.x, mouse_pointer.y, 0, window, nullptr); + break; + } + case WM_LBUTTONUP: + { + // ignore event if this is the second click of a double click + if (!double_click_timer_running) + { + // start timer for detecting single or double click + double_click_timer_running = true; + double_clicked = false; + + UINT doubleClickTime = GetDoubleClickTime(); + std::thread([doubleClickTime]() { + std::this_thread::sleep_for(std::chrono::milliseconds(doubleClickTime)); + click_timer_elapsed(); + }).detach(); + } + break; + } + case WM_LBUTTONDBLCLK: + { + double_clicked = true; + open_settings_window(std::nullopt, false); + break; } break; } diff --git a/src/runner/tray_icon.h b/src/runner/tray_icon.h index e65fa9720f..0d63475d21 100644 --- a/src/runner/tray_icon.h +++ b/src/runner/tray_icon.h @@ -7,7 +7,7 @@ void start_tray_icon(); // Stop the Tray Icon void stop_tray_icon(); // Open the Settings Window -void open_settings_window(std::optional settings_window); +void open_settings_window(std::optional settings_window, bool show_flyout); // Callback type to be called by the tray icon loop typedef void (*main_loop_callback_function)(PVOID); // Calls a callback in _callback diff --git a/src/settings-ui/Settings.UI.Library/EnabledModules.cs b/src/settings-ui/Settings.UI.Library/EnabledModules.cs index de29ae6d35..ea055fb4cd 100644 --- a/src/settings-ui/Settings.UI.Library/EnabledModules.cs +++ b/src/settings-ui/Settings.UI.Library/EnabledModules.cs @@ -2,6 +2,7 @@ // 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.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; @@ -12,6 +13,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library { public class EnabledModules { + private Action notifyEnabledChangedAction; + public EnabledModules() { } @@ -28,6 +31,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); fancyZones = value; + NotifyChange(); } } } @@ -76,6 +80,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); shortcutGuide = value; + NotifyChange(); } } } @@ -139,6 +144,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); powerLauncher = value; + NotifyChange(); } } } @@ -155,6 +161,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); colorPicker = value; + NotifyChange(); } } } @@ -267,6 +274,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); powerOCR = value; + NotifyChange(); } } } @@ -283,6 +291,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); measureTool = value; + NotifyChange(); } } } @@ -299,6 +308,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { LogTelemetryEvent(value); hosts = value; + NotifyChange(); } } } @@ -319,6 +329,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library } } + private void NotifyChange() + { + notifyEnabledChangedAction?.Invoke(); + } + public string ToJsonString() { return JsonSerializer.Serialize(this); @@ -333,5 +348,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library }; PowerToysTelemetry.Log.WriteEvent(dataEvent); } + + internal void AddEnabledModuleChangeNotification(Action callBack) + { + notifyEnabledChangedAction = callBack; + } } } diff --git a/src/settings-ui/Settings.UI.Library/GeneralSettings.cs b/src/settings-ui/Settings.UI.Library/GeneralSettings.cs index be57f43c8b..25bd1b2a07 100644 --- a/src/settings-ui/Settings.UI.Library/GeneralSettings.cs +++ b/src/settings-ui/Settings.UI.Library/GeneralSettings.cs @@ -108,5 +108,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library return false; } + + public void AddEnabledModuleChangeNotification(Action callBack) + { + Enabled.AddEnabledModuleChangeNotification(callBack); + } } } diff --git a/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutActivatedEvent.cs b/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutActivatedEvent.cs new file mode 100644 index 0000000000..8e075aea0c --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutActivatedEvent.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class TrayFlyoutActivatedEvent : EventBase, IEvent + { + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutModuleRunEvent.cs b/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutModuleRunEvent.cs new file mode 100644 index 0000000000..c1813e9adb --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/Telemetry/Events/TrayFlyoutModuleRunEvent.cs @@ -0,0 +1,18 @@ +// 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.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class TrayFlyoutModuleRunEvent : EventBase, IEvent + { + public string ModuleName { get; set; } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Settings.UI/App.xaml b/src/settings-ui/Settings.UI/App.xaml index 3858e4f7d2..b4e581d64d 100644 --- a/src/settings-ui/Settings.UI/App.xaml +++ b/src/settings-ui/Settings.UI/App.xaml @@ -3,6 +3,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls" + xmlns:local="using:Microsoft.PowerToys.Settings.UI" xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" xmlns:labs="using:CommunityToolkit.Labs.WinUI"> diff --git a/src/settings-ui/Settings.UI/App.xaml.cs b/src/settings-ui/Settings.UI/App.xaml.cs index 7f10ecf0b1..d07bc645d3 100644 --- a/src/settings-ui/Settings.UI/App.xaml.cs +++ b/src/settings-ui/Settings.UI/App.xaml.cs @@ -13,6 +13,7 @@ using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events; using Microsoft.PowerToys.Settings.UI.Library.Utilities; +using Microsoft.PowerToys.Settings.UI.Views; using Microsoft.PowerToys.Telemetry; using Microsoft.UI.Xaml; using Windows.UI.Popups; @@ -35,12 +36,13 @@ namespace Microsoft.PowerToys.Settings.UI IsUserAdmin, ShowOobeWindow, ShowScoobeWindow, + ShowFlyout, SettingsWindow, } // Quantity of arguments - private const int RequiredArgumentsQty = 9; - private const int RequiredAndOptionalArgumentsQty = 10; + private const int RequiredArgumentsQty = 10; + private const int RequiredAndOptionalArgumentsQty = 11; // Create an instance of the IPC wrapper. private static TwoWayPipeMessageIPCManaged ipcmanager; @@ -53,6 +55,8 @@ namespace Microsoft.PowerToys.Settings.UI public bool ShowOobe { get; set; } + public bool ShowFlyout { get; set; } + public bool ShowScoobe { get; set; } public Type StartupPage { get; set; } = typeof(Views.GeneralPage); @@ -71,15 +75,24 @@ namespace Microsoft.PowerToys.Settings.UI this.InitializeComponent(); } - public static void OpenSettingsWindow(Type type) + public static void OpenSettingsWindow(Type type = null, bool ensurePageIsSelected = false) { if (settingsWindow == null) { settingsWindow = new MainWindow(IsDarkTheme()); + type = typeof(GeneralPage); } settingsWindow.Activate(); - settingsWindow.NavigateToSection(type); + if (type != null) + { + settingsWindow.NavigateToSection(type); + } + + if (ensurePageIsSelected) + { + settingsWindow.EnsurePageIsSelected(); + } } /// @@ -90,6 +103,7 @@ namespace Microsoft.PowerToys.Settings.UI protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { var cmdArgs = Environment.GetCommandLineArgs(); + var isDark = IsDarkTheme(); if (cmdArgs != null && cmdArgs.Length >= RequiredArgumentsQty) @@ -107,6 +121,7 @@ namespace Microsoft.PowerToys.Settings.UI IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true"; ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true"; ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true"; + ShowFlyout = cmdArgs[(int)Arguments.ShowFlyout] == "true"; if (cmdArgs.Length == RequiredAndOptionalArgumentsQty) { @@ -149,7 +164,7 @@ namespace Microsoft.PowerToys.Settings.UI }); ipcmanager.Start(); - if (!ShowOobe && !ShowScoobe) + if (!ShowOobe && !ShowScoobe && !ShowFlyout) { settingsWindow = new MainWindow(isDark); settingsWindow.Activate(); @@ -176,6 +191,10 @@ namespace Microsoft.PowerToys.Settings.UI scoobeWindow.Activate(); SetOobeWindow(scoobeWindow); } + else if (ShowFlyout) + { + ShellPage.OpenFlyoutCallback(); + } } } else @@ -277,6 +296,7 @@ namespace Microsoft.PowerToys.Settings.UI private static MainWindow settingsWindow; private static OobeWindow oobeWindow; + private static FlyoutWindow flyoutWindow; private static ThemeListener themeListener; public static void ClearSettingsWindow() @@ -294,14 +314,29 @@ namespace Microsoft.PowerToys.Settings.UI return oobeWindow; } + public static FlyoutWindow GetFlyoutWindow() + { + return flyoutWindow; + } + public static void SetOobeWindow(OobeWindow window) { oobeWindow = window; } + public static void SetFlyoutWindow(FlyoutWindow window) + { + flyoutWindow = window; + } + public static void ClearOobeWindow() { oobeWindow = null; } + + public static void ClearFlyoutWindow() + { + flyoutWindow = null; + } } } diff --git a/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.cs b/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.cs new file mode 100644 index 0000000000..17c901cbba --- /dev/null +++ b/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.cs @@ -0,0 +1,43 @@ +// 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 CommunityToolkit.Labs.WinUI; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using WinUIEx; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public partial class FlyoutMenuButton : Button + { + /// + /// The backing for the property. + /// + public static readonly DependencyProperty IconProperty = DependencyProperty.Register( + nameof(Icon), + typeof(object), + typeof(FlyoutMenuButton), + new PropertyMetadata(defaultValue: null)); + + /// + /// Gets or sets the icon. + /// + public object Icon + { + get => (object)GetValue(IconProperty); + set => SetValue(IconProperty, value); + } + + public FlyoutMenuButton() + { + this.DefaultStyleKey = typeof(FlyoutMenuButton); + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + } + } +} diff --git a/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.xaml b/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.xaml new file mode 100644 index 0000000000..e9b3a6a55f --- /dev/null +++ b/src/settings-ui/Settings.UI/Controls/FlyoutMenuButton/FlyoutMenuButton.xaml @@ -0,0 +1,104 @@ + + + + + + + diff --git a/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml b/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml new file mode 100644 index 0000000000..85a9fa0f10 --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml.cs b/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml.cs new file mode 100644 index 0000000000..6692ff6077 --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/AppsListPage.xaml.cs @@ -0,0 +1,36 @@ +// 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 System.Threading; +using global::Windows.System; +using interop; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.PowerToys.Settings.UI.ViewModels; +using Microsoft.PowerToys.Settings.UI.Views; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; + +namespace Microsoft.PowerToys.Settings.UI.Flyout +{ + public sealed partial class AppsListPage : Page + { + private AllAppsViewModel ViewModel { get; set; } + + public AppsListPage() + { + this.InitializeComponent(); + + var settingsUtils = new SettingsUtils(); + ViewModel = new AllAppsViewModel(SettingsRepository.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage); + DataContext = ViewModel; + } + + private void BackButton_Click(object sender, RoutedEventArgs e) + { + Frame.Navigate(typeof(LaunchPage), null, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromLeft }); + } + } +} diff --git a/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml b/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml new file mode 100644 index 0000000000..05d035275b --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml.cs b/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml.cs new file mode 100644 index 0000000000..c921aeb4e0 --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml.cs @@ -0,0 +1,140 @@ +// 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 System.Threading; +using global::Windows.System; +using interop; +using Microsoft.PowerToys.Settings.UI.Controls; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events; +using Microsoft.PowerToys.Settings.UI.ViewModels; +using Microsoft.PowerToys.Settings.UI.Views; +using Microsoft.PowerToys.Telemetry; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; + +namespace Microsoft.PowerToys.Settings.UI.Flyout +{ + public sealed partial class LaunchPage : Page + { + private LauncherViewModel ViewModel { get; set; } + + public LaunchPage() + { + this.InitializeComponent(); + var settingsUtils = new SettingsUtils(); + ViewModel = new LauncherViewModel(SettingsRepository.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage); + DataContext = ViewModel; + } + + private void ModuleButton_Click(object sender, RoutedEventArgs e) + { + FlyoutMenuButton selectedModuleBtn = sender as FlyoutMenuButton; + bool moduleRun = true; + switch ((string)selectedModuleBtn.Tag) + { + case "ColorPicker": // Launch ColorPicker + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent())) + { + eventHandle.Set(); + } + + break; + case "FancyZones": // Launch FancyZones Editor + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent())) + { + eventHandle.Set(); + } + + break; + + case "Hosts": // Launch Hosts + { + bool launchAdmin = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator; + var actionName = "Launch"; + if (!App.IsElevated && launchAdmin) + { + actionName = "LaunchAdministrator"; + } + + Views.ShellPage.SendDefaultIPCMessage("{\"action\":{\"Hosts\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}"); + } + + break; + + case "MeasureTool": // Launch Screen Ruler + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent())) + { + eventHandle.Set(); + } + + break; + + case "PowerLauncher": // Launch Run + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent())) + { + eventHandle.Set(); + } + + break; + + case "PowerOCR": // Launch Text Extractor + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent())) + { + eventHandle.Set(); + } + + break; + + case "ShortcutGuide": // Launch Shortcut Guide + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent())) + { + eventHandle.Set(); + } + + break; + + default: + moduleRun = false; + break; + } + + if (moduleRun) + { + PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutModuleRunEvent() { ModuleName = (string)selectedModuleBtn.Tag }); + } + } + + private void SettingsBtn_Click(object sender, RoutedEventArgs e) + { + App.OpenSettingsWindow(null, true); + } + + private async void DocsBtn_Click(object sender, RoutedEventArgs e) + { + await Launcher.LaunchUriAsync(new Uri("https://aka.ms/PowerToysOverview")); + } + + private void AllAppButton_Click(object sender, RoutedEventArgs e) + { + Frame.Navigate(typeof(AppsListPage), null, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); + } + + private void QuitButton_Click(object sender, RoutedEventArgs e) + { + ViewModel.KillRunner(); + this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + Application.Current.Exit(); + }); + } + + private void ReportBugBtn_Click(object sender, RoutedEventArgs e) + { + ViewModel.StartBugReport(); + } + } +} diff --git a/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml b/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml new file mode 100644 index 0000000000..52b5f542ca --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml.cs b/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml.cs new file mode 100644 index 0000000000..fe0aa75f69 --- /dev/null +++ b/src/settings-ui/Settings.UI/Flyout/ShellPage.xaml.cs @@ -0,0 +1,30 @@ +// 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.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; + +namespace Microsoft.PowerToys.Settings.UI.Flyout +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class ShellPage : Page + { + public ShellPage() + { + this.InitializeComponent(); + } + + internal void SwitchToLaunchPage() + { + ContentFrame.Navigate(typeof(LaunchPage), null, new SuppressNavigationTransitionInfo()); + } + + private void Page_Loaded(object sender, RoutedEventArgs e) + { + SwitchToLaunchPage(); + } + } +} diff --git a/src/settings-ui/Settings.UI/FlyoutWindow.xaml b/src/settings-ui/Settings.UI/FlyoutWindow.xaml new file mode 100644 index 0000000000..d3c5524d47 --- /dev/null +++ b/src/settings-ui/Settings.UI/FlyoutWindow.xaml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/src/settings-ui/Settings.UI/FlyoutWindow.xaml.cs b/src/settings-ui/Settings.UI/FlyoutWindow.xaml.cs new file mode 100644 index 0000000000..aa2ab39849 --- /dev/null +++ b/src/settings-ui/Settings.UI/FlyoutWindow.xaml.cs @@ -0,0 +1,51 @@ +// 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.Settings.UI.Library.Telemetry.Events; +using Microsoft.PowerToys.Settings.UI.ViewModels.Flyout; +using Microsoft.PowerToys.Telemetry; +using Microsoft.UI; +using Microsoft.UI.Windowing; +using WinUIEx; + +namespace Microsoft.PowerToys.Settings.UI +{ + /// + /// An empty window that can be used on its own or navigated to within a Frame. + /// + public sealed partial class FlyoutWindow : WindowEx + { + private const int WindowWidth = 386; + private const int WindowHeight = 486; + private const int WindowMargin = 12; + + public FlyoutViewModel ViewModel { get; set; } + + public FlyoutWindow() + { + this.InitializeComponent(); + this.Activated += FlyoutWindow_Activated; + var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this); + WindowId windowId = Win32Interop.GetWindowIdFromWindow(hwnd); + DisplayArea displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest); + double dpiScale = (float)this.GetDpiForWindow() / 96; + double x = displayArea.WorkArea.Width - (dpiScale * (WindowWidth + WindowMargin)); + double y = displayArea.WorkArea.Height - (dpiScale * (WindowHeight + WindowMargin)); + this.MoveAndResize(x, y, WindowWidth, WindowHeight); + ViewModel = new FlyoutViewModel(); + } + + private void FlyoutWindow_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args) + { + PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutActivatedEvent()); + if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.Deactivated) + { + if (ViewModel.CanHide) + { + FlyoutShellPage.SwitchToLaunchPage(); + this.Hide(); + } + } + } + } +} diff --git a/src/settings-ui/Settings.UI/Helpers/IRefreshablePage.cs b/src/settings-ui/Settings.UI/Helpers/IRefreshablePage.cs new file mode 100644 index 0000000000..d37cb294a1 --- /dev/null +++ b/src/settings-ui/Settings.UI/Helpers/IRefreshablePage.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. + +// An interface so that pages can define refresh method to refresh their view models. +namespace Microsoft.PowerToys.Settings.UI.Helpers +{ + public interface IRefreshablePage + { + void RefreshEnabledState(); + } +} diff --git a/src/settings-ui/Settings.UI/Helpers/NativeMethods.cs b/src/settings-ui/Settings.UI/Helpers/NativeMethods.cs index d247c03f1c..8a7bdb29e7 100644 --- a/src/settings-ui/Settings.UI/Helpers/NativeMethods.cs +++ b/src/settings-ui/Settings.UI/Helpers/NativeMethods.cs @@ -51,6 +51,9 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers [DllImport("user32.dll")] public static extern bool AllowSetForegroundWindow(int dwProcessId); + [System.Runtime.InteropServices.DllImport("User32.dll")] + public static extern bool SetForegroundWindow(IntPtr handle); + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr LoadLibrary(string dllToLoad); diff --git a/src/settings-ui/Settings.UI/Helpers/Utils.cs b/src/settings-ui/Settings.UI/Helpers/Utils.cs index d075ccf9c4..53124c7986 100644 --- a/src/settings-ui/Settings.UI/Helpers/Utils.cs +++ b/src/settings-ui/Settings.UI/Helpers/Utils.cs @@ -45,5 +45,13 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers { } } + + public static void BecomeForegroundWindow(IntPtr hWnd) + { + NativeKeyboardHelper.INPUT input = new NativeKeyboardHelper.INPUT { type = NativeKeyboardHelper.INPUTTYPE.INPUT_MOUSE, data = { } }; + NativeKeyboardHelper.INPUT[] inputs = new NativeKeyboardHelper.INPUT[] { input }; + _ = NativeMethods.SendInput(1, inputs, NativeKeyboardHelper.INPUT.Size); + NativeMethods.SetForegroundWindow(hWnd); + } } } diff --git a/src/settings-ui/Settings.UI/MainWindow.xaml.cs b/src/settings-ui/Settings.UI/MainWindow.xaml.cs index 8723a01110..54cc7430d3 100644 --- a/src/settings-ui/Settings.UI/MainWindow.xaml.cs +++ b/src/settings-ui/Settings.UI/MainWindow.xaml.cs @@ -6,6 +6,7 @@ using System; using ManagedCommon; using Microsoft.PowerLauncher.Telemetry; using Microsoft.PowerToys.Settings.UI.Helpers; +using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Views; using Microsoft.PowerToys.Telemetry; @@ -14,6 +15,7 @@ using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Windows.ApplicationModel.Resources; using Windows.Data.Json; +using WinUIEx; namespace Microsoft.PowerToys.Settings.UI { @@ -73,6 +75,90 @@ namespace Microsoft.PowerToys.Settings.UI App.GetTwoWayIPCManager()?.Send(msg); }); + // open main window + ShellPage.SetOpenMainWindowCallback(() => + { + this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + App.OpenSettingsWindow(typeof(GeneralPage))); + }); + + // open main window + ShellPage.SetUpdatingGeneralSettingsCallback((string module, bool isEnabled) => + { + SettingsRepository repository = SettingsRepository.GetInstance(new SettingsUtils()); + GeneralSettings generalSettingsConfig = repository.SettingsConfig; + bool needToUpdate = false; + switch (module) + { + case "AlwaysOnTop": + needToUpdate = generalSettingsConfig.Enabled.AlwaysOnTop != isEnabled; + generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break; + case "Awake": + needToUpdate = generalSettingsConfig.Enabled.Awake != isEnabled; + generalSettingsConfig.Enabled.Awake = isEnabled; break; + case "ColorPicker": + needToUpdate = generalSettingsConfig.Enabled.ColorPicker != isEnabled; + generalSettingsConfig.Enabled.ColorPicker = isEnabled; break; + case "FancyZones": + needToUpdate = generalSettingsConfig.Enabled.FancyZones != isEnabled; + generalSettingsConfig.Enabled.FancyZones = isEnabled; break; + case "FileLocksmith": + needToUpdate = generalSettingsConfig.Enabled.FileLocksmith != isEnabled; + generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break; + case "FindMyMouse": + needToUpdate = generalSettingsConfig.Enabled.FindMyMouse != isEnabled; + generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break; + case "Hosts": + needToUpdate = generalSettingsConfig.Enabled.Hosts != isEnabled; + generalSettingsConfig.Enabled.Hosts = isEnabled; break; + case "ImageResizer": + needToUpdate = generalSettingsConfig.Enabled.ImageResizer != isEnabled; + generalSettingsConfig.Enabled.ImageResizer = isEnabled; break; + case "KeyboardManager": + needToUpdate = generalSettingsConfig.Enabled.KeyboardManager != isEnabled; + generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break; + case "MouseHighlighter": + needToUpdate = generalSettingsConfig.Enabled.MouseHighlighter != isEnabled; + generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break; + case "MousePointerCrosshairs": + needToUpdate = generalSettingsConfig.Enabled.MousePointerCrosshairs != isEnabled; + generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break; + case "PowerRename": + needToUpdate = generalSettingsConfig.Enabled.PowerRename != isEnabled; + generalSettingsConfig.Enabled.PowerRename = isEnabled; break; + case "PowerLauncher": + needToUpdate = generalSettingsConfig.Enabled.PowerLauncher != isEnabled; + generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break; + case "PowerAccent": + needToUpdate = generalSettingsConfig.Enabled.PowerAccent != isEnabled; + generalSettingsConfig.Enabled.PowerAccent = isEnabled; break; + case "MeasureTool": + needToUpdate = generalSettingsConfig.Enabled.MeasureTool != isEnabled; + generalSettingsConfig.Enabled.MeasureTool = isEnabled; break; + case "ShortcutGuide": + needToUpdate = generalSettingsConfig.Enabled.ShortcutGuide != isEnabled; + generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break; + case "PowerOCR": + needToUpdate = generalSettingsConfig.Enabled.PowerOCR != isEnabled; + generalSettingsConfig.Enabled.PowerOCR = isEnabled; break; + case "VideoConference": + needToUpdate = generalSettingsConfig.Enabled.VideoConference != isEnabled; + generalSettingsConfig.Enabled.VideoConference = isEnabled; break; + } + + if (needToUpdate) + { + var outgoing = new OutGoingGeneralSettings(generalSettingsConfig); + this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + ShellPage.SendDefaultIPCMessage(outgoing.ToString()); + ShellPage.ShellHandler?.SignalGeneralDataUpdate(); + }); + } + + return needToUpdate; + }); + // open oobe ShellPage.SetOpenOobeCallback(() => { @@ -84,6 +170,39 @@ namespace Microsoft.PowerToys.Settings.UI App.GetOobeWindow().Activate(); }); + // open flyout + ShellPage.SetOpenFlyoutCallback(() => + { + this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + if (App.GetFlyoutWindow() == null) + { + App.SetFlyoutWindow(new FlyoutWindow()); + } + + FlyoutWindow flyout = App.GetFlyoutWindow(); + flyout.Activate(); + + // https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground + // Need to call SetForegroundWindow to actually gain focus. + Utils.BecomeForegroundWindow(flyout.GetWindowHandle()); + }); + }); + + // disable flyout hiding + ShellPage.SetDisableFlyoutHidingCallback(() => + { + this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + if (App.GetFlyoutWindow() == null) + { + App.SetFlyoutWindow(new FlyoutWindow()); + } + + App.GetFlyoutWindow().ViewModel.DisableHiding(); + }); + }); + this.InitializeComponent(); // receive IPC Message @@ -140,5 +259,10 @@ namespace Microsoft.PowerToys.Settings.UI NativeMethods.ShowWindow(hWnd, NativeMethods.SW_HIDE); } } + + internal void EnsurePageIsSelected() + { + ShellPage.EnsurePageIsSelected(); + } } } diff --git a/src/settings-ui/Settings.UI/PowerToys.Settings.csproj b/src/settings-ui/Settings.UI/PowerToys.Settings.csproj index 9c2c9272db..d9b78b6e41 100644 --- a/src/settings-ui/Settings.UI/PowerToys.Settings.csproj +++ b/src/settings-ui/Settings.UI/PowerToys.Settings.csproj @@ -59,6 +59,14 @@ + + + + + + + + @@ -74,6 +82,7 @@ + @@ -92,9 +101,24 @@ + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + MSBuild:Compile + + MSBuild:Compile + + + MSBuild:Compile + Always diff --git a/src/settings-ui/Settings.UI/Services/NavigationService.cs b/src/settings-ui/Settings.UI/Services/NavigationService.cs index 2e3ddea898..be720e2ec6 100644 --- a/src/settings-ui/Settings.UI/Services/NavigationService.cs +++ b/src/settings-ui/Settings.UI/Services/NavigationService.cs @@ -101,5 +101,13 @@ namespace Microsoft.PowerToys.Settings.UI.Services private static void Frame_NavigationFailed(object sender, NavigationFailedEventArgs e) => NavigationFailed?.Invoke(sender, e); private static void Frame_Navigated(object sender, NavigationEventArgs e) => Navigated?.Invoke(sender, e); + + internal static void EnsurePageIsSelected(Type pageType) + { + if (Frame.Content == null) + { + Frame.Navigate(pageType); + } + } } } diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 74bcd3d3d2..7ca657c387 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -895,7 +895,7 @@ Remove Removes a user defined setting group for Image Resizer - + Delete @@ -2693,7 +2693,7 @@ Activate by holding the key for the character you want to add an accent to, then Start selection from the left - + Start selection from the leftmost character for all activation keys, including left and right arrows @@ -2888,4 +2888,47 @@ Activate by holding the key for the character you want to add an accent to, then Preferred language - + + All apps + + + Back + + + Back + + + Bug report + + + Bug report + + + Documentation + + + Documentation + + + FancyZones Editor + Do not localize this string + + + More + + + More + + + Settings + + + Settings + + + Shortcuts + + + Update available + + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI/Styles/Button.xaml b/src/settings-ui/Settings.UI/Styles/Button.xaml index 6e60ec3530..dd324e9a92 100644 --- a/src/settings-ui/Settings.UI/Styles/Button.xaml +++ b/src/settings-ui/Settings.UI/Styles/Button.xaml @@ -1,35 +1,15 @@ - + - - - - - - - - + + + + + + + + - - + + diff --git a/src/settings-ui/Settings.UI/Styles/TextBlock.xaml b/src/settings-ui/Settings.UI/Styles/TextBlock.xaml index 806bf88118..2af0b66b0d 100644 --- a/src/settings-ui/Settings.UI/Styles/TextBlock.xaml +++ b/src/settings-ui/Settings.UI/Styles/TextBlock.xaml @@ -18,10 +18,15 @@ 12 - + + 12 + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI/Themes/Generic.xaml b/src/settings-ui/Settings.UI/Themes/Generic.xaml index bec1641aaa..45fb5d42e3 100644 --- a/src/settings-ui/Settings.UI/Themes/Generic.xaml +++ b/src/settings-ui/Settings.UI/Themes/Generic.xaml @@ -1,9 +1,8 @@ - + + diff --git a/src/settings-ui/Settings.UI/ViewModels/AlwaysOnTopViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/AlwaysOnTopViewModel.cs index 120a93cd12..6dff77c18a 100644 --- a/src/settings-ui/Settings.UI/ViewModels/AlwaysOnTopViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/AlwaysOnTopViewModel.cs @@ -41,6 +41,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; + InitializeEnabledValue(); + // To obtain the settings configurations of AlwaysOnTop. if (moduleSettingsRepository == null) { @@ -49,18 +51,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings = moduleSettingsRepository.SettingsConfig; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.AlwaysOnTop; - } - _hotkey = Settings.Properties.Hotkey.Value; _frameEnabled = Settings.Properties.FrameEnabled.Value; _frameThickness = Settings.Properties.FrameThickness.Value; @@ -76,6 +66,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SendConfigMSG = ipcMSGCallBackFunc; } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.AlwaysOnTop; + } + } + public bool IsEnabled { get => _isEnabled; @@ -274,6 +279,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SettingsUtils.SaveSettings(Settings.ToJsonString(), AlwaysOnTopSettings.ModuleName); } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; diff --git a/src/settings-ui/Settings.UI/ViewModels/AwakeViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/AwakeViewModel.cs index 609f028f6d..1b122f32b6 100644 --- a/src/settings-ui/Settings.UI/ViewModels/AwakeViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/AwakeViewModel.cs @@ -37,6 +37,19 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings = moduleSettingsRepository.SettingsConfig; + InitializeEnabledValue(); + + _keepDisplayOn = Settings.Properties.KeepDisplayOn; + _mode = Settings.Properties.Mode; + _hours = Settings.Properties.Hours; + _minutes = Settings.Properties.Minutes; + + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredAwakeEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -48,14 +61,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isEnabled = GeneralSettingsConfig.Enabled.Awake; } - - _keepDisplayOn = Settings.Properties.KeepDisplayOn; - _mode = Settings.Properties.Mode; - _hours = Settings.Properties.Hours; - _minutes = Settings.Properties.Minutes; - - // set the callback functions value to hangle outgoing IPC message. - SendConfigMSG = ipcMSGCallBackFunc; } public bool IsEnabled @@ -179,6 +184,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + OnPropertyChanged(nameof(IsTimeConfigurationEnabled)); + OnPropertyChanged(nameof(IsScreenConfigurationPossibleEnabled)); + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; diff --git a/src/settings-ui/Settings.UI/ViewModels/ColorPickerViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ColorPickerViewModel.cs index b193758438..c9c06e4fd9 100644 --- a/src/settings-ui/Settings.UI/ViewModels/ColorPickerViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/ColorPickerViewModel.cs @@ -69,6 +69,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _colorPickerSettings = colorPickerSettingsRepository.SettingsConfig; // used in the unit tests } + InitializeEnabledValue(); + + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + + _delayedTimer = new Timer(); + _delayedTimer.Interval = SaveSettingsDelayInMs; + _delayedTimer.Elapsed += DelayedTimer_Tick; + _delayedTimer.AutoReset = false; + + InitializeColorFormats(); + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredColorPickerEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -80,16 +95,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isEnabled = GeneralSettingsConfig.Enabled.ColorPicker; } - - // set the callback functions value to hangle outgoing IPC message. - SendConfigMSG = ipcMSGCallBackFunc; - - _delayedTimer = new Timer(); - _delayedTimer.Interval = SaveSettingsDelayInMs; - _delayedTimer.Elapsed += DelayedTimer_Tick; - _delayedTimer.AutoReset = false; - - InitializeColorFormats(); } public bool IsEnabled @@ -360,6 +365,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels JsonSerializer.Serialize(_colorPickerSettings))); } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } + protected virtual void Dispose(bool disposing) { if (!disposedValue) diff --git a/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs index ee9330e0c2..b385eb23dc 100644 --- a/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs @@ -116,6 +116,19 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels string numberColor = Settings.Properties.FancyzonesNumberColor.Value; _zoneNumberColor = !string.IsNullOrEmpty(numberColor) ? numberColor : ConfigDefaults.DefaultFancyzonesNumberColor; + InitializeEnabledValue(); + + _windows11 = Helper.Windows11(); + + // Disable setting on windows 10 + if (!_windows11 && DisableRoundCornersOnWindowSnap) + { + DisableRoundCornersOnWindowSnap = false; + } + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredFancyZonesEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -127,14 +140,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isEnabled = GeneralSettingsConfig.Enabled.FancyZones; } - - _windows11 = Helper.Windows11(); - - // Disable setting on windows 10 - if (!_windows11 && DisableRoundCornersOnWindowSnap) - { - DisableRoundCornersOnWindowSnap = false; - } } private GpoRuleConfigured _enabledGpoRuleConfiguration; @@ -883,5 +888,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels OnPropertyChanged(propertyName); SettingsUtils.SaveSettings(Settings.ToJsonString(), GetSettingsSubPath()); } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + OnPropertyChanged(nameof(SnapHotkeysCategoryEnabled)); + OnPropertyChanged(nameof(QuickSwitchEnabled)); + OnPropertyChanged(nameof(WindowSwitchingCategoryEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/FileLocksmithViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/FileLocksmithViewModel.cs index dc598a3caa..b93e4cefc1 100644 --- a/src/settings-ui/Settings.UI/ViewModels/FileLocksmithViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/FileLocksmithViewModel.cs @@ -24,6 +24,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; + InitializeEnabledValue(); + + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredFileLocksmithEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -35,9 +43,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isFileLocksmithEnabled = GeneralSettingsConfig.Enabled.FileLocksmith; } - - // set the callback functions value to hangle outgoing IPC message. - SendConfigMSG = ipcMSGCallBackFunc; } public bool IsFileLocksmithEnabled @@ -77,5 +82,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isFileLocksmithEnabled; + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsFileLocksmithEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs new file mode 100644 index 0000000000..af05e8b721 --- /dev/null +++ b/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs @@ -0,0 +1,163 @@ +// 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 System.Threading.Tasks; +using global::PowerToys.GPOWrapper; +using Microsoft.PowerToys.Settings.UI.Flyout; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.PowerToys.Settings.UI.Library.Helpers; +using Microsoft.PowerToys.Settings.UI.Library.Interfaces; +using Windows.ApplicationModel.Resources; + +namespace Microsoft.PowerToys.Settings.UI.ViewModels +{ + public class AllAppsViewModel : Observable + { + public ObservableCollection FlyoutMenuItems { get; set; } + + private ISettingsRepository _settingsRepository; + private GeneralSettings generalSettingsConfig; + + private Func SendConfigMSG { get; } + + public AllAppsViewModel(ISettingsRepository settingsRepository, Func ipcMSGCallBackFunc) + { + _settingsRepository = settingsRepository; + generalSettingsConfig = settingsRepository.SettingsConfig; + generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage); + + FlyoutMenuItems = new ObservableCollection(); + + ResourceLoader resourceLoader = ResourceLoader.GetForViewIndependentUse(); + GpoRuleConfigured gpo; + if ((gpo = GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("AlwaysOnTop/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.AlwaysOnTop, Tag = "AlwaysOnTop", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsAlwaysOnTop.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredAwakeEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("Awake/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.Awake, Tag = "Awake", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsAwake.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredColorPickerEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("ColorPicker/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.ColorPicker, Tag = "ColorPicker", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsColorPicker.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredFancyZonesEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("FancyZones/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.FancyZones, Tag = "FancyZones", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsFancyZones.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredFileLocksmithEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("FileLocksmith/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.FileLocksmith, Tag = "FileLocksmith", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsFileLocksmith.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredFindMyMouseEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MouseUtils_FindMyMouse/Header"), IsEnabled = generalSettingsConfig.Enabled.FindMyMouse, Tag = "FindMyMouse", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsFindMyMouse.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredHostsFileEditorEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("Hosts/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.Hosts, Tag = "Hosts", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsHosts.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredImageResizerEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("ImageResizer/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.ImageResizer, Tag = "ImageResizer", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsImageResizer.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredKeyboardManagerEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("KeyboardManager/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.KeyboardManager, Tag = "KeyboardManager", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsKeyboardManager.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredMouseHighlighterEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MouseUtils_MouseHighlighter/Header"), IsEnabled = generalSettingsConfig.Enabled.MouseHighlighter, Tag = "MouseHighlighter", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsMouseHighlighter.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MouseUtils_MousePointerCrosshairs/Header"), IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs, Tag = "MousePointerCrosshairs", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsMouseCrosshairs.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredPowerRenameEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("PowerRename/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PowerRename, Tag = "PowerRename", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerRename.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredPowerLauncherEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("PowerLauncher/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PowerLauncher, Tag = "PowerLauncher", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerToysRun.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredQuickAccentEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("QuickAccent/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PowerAccent, Tag = "PowerAccent", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerAccent.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredScreenRulerEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MeasureTool/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.MeasureTool, Tag = "MeasureTool", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsScreenRuler.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredShortcutGuideEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("ShortcutGuide/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.ShortcutGuide, Tag = "ShortcutGuide", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsShortcutGuide.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + if ((gpo = GPOWrapper.GetConfiguredTextExtractorEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("TextExtractor/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PowerOCR, Tag = "PowerOCR", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerOCR.png", EnabledChangedCallback = EnabledChangedOnUI }); + } + + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + } + + private void EnabledChangedOnUI(FlyoutMenuItem flyoutMenuItem) + { + if (Views.ShellPage.UpdateGeneralSettingsCallback(flyoutMenuItem.Tag, flyoutMenuItem.IsEnabled)) + { + Views.ShellPage.DisableFlyoutHidingCallback(); + } + } + + private void ModuleEnabledChangedOnSettingsPage() + { + generalSettingsConfig = _settingsRepository.SettingsConfig; + generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage); + foreach (FlyoutMenuItem item in FlyoutMenuItems) + { + switch (item.Tag) + { + case "AlwaysOnTop": item.IsEnabled = generalSettingsConfig.Enabled.AlwaysOnTop; break; + case "Awake": item.IsEnabled = generalSettingsConfig.Enabled.Awake; break; + case "ColorPicker": item.IsEnabled = generalSettingsConfig.Enabled.ColorPicker; break; + case "FancyZones": item.IsEnabled = generalSettingsConfig.Enabled.FancyZones; break; + case "FileLocksmith": item.IsEnabled = generalSettingsConfig.Enabled.FileLocksmith; break; + case "FindMyMouse": item.IsEnabled = generalSettingsConfig.Enabled.FindMyMouse; break; + case "Hosts": item.IsEnabled = generalSettingsConfig.Enabled.Hosts; break; + case "ImageResizer": item.IsEnabled = generalSettingsConfig.Enabled.ImageResizer; break; + case "KeyboardManager": item.IsEnabled = generalSettingsConfig.Enabled.KeyboardManager; break; + case "MouseHighlighter": item.IsEnabled = generalSettingsConfig.Enabled.MouseHighlighter; break; + case "MousePointerCrosshairs": item.IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs; break; + case "PowerRename": item.IsEnabled = generalSettingsConfig.Enabled.PowerRename; break; + case "PowerLauncher": item.IsEnabled = generalSettingsConfig.Enabled.PowerLauncher; break; + case "PowerAccent": item.IsEnabled = generalSettingsConfig.Enabled.PowerAccent; break; + case "MeasureTool": item.IsEnabled = generalSettingsConfig.Enabled.MeasureTool; break; + case "ShortcutGuide": item.IsEnabled = generalSettingsConfig.Enabled.ShortcutGuide; break; + case "PowerOCR": item.IsEnabled = generalSettingsConfig.Enabled.PowerOCR; break; + case "VideoConference": item.IsEnabled = generalSettingsConfig.Enabled.VideoConference; break; + } + } + } + } +} diff --git a/src/settings-ui/Settings.UI/ViewModels/Flyout/FlyoutMenuItem.cs b/src/settings-ui/Settings.UI/ViewModels/Flyout/FlyoutMenuItem.cs new file mode 100644 index 0000000000..c8b184b2f1 --- /dev/null +++ b/src/settings-ui/Settings.UI/ViewModels/Flyout/FlyoutMenuItem.cs @@ -0,0 +1,61 @@ +// 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 Microsoft.UI.Xaml; + +namespace Microsoft.PowerToys.Settings.UI.ViewModels +{ + public class FlyoutMenuItem : INotifyPropertyChanged + { + private bool _visible; + private bool _isEnabled; + + public string Label { get; set; } + + public string Icon { get; set; } + + public string ToolTip { get; set; } + + public string Tag { get; set; } + + public bool IsEnabled + { + get => _isEnabled; + set + { + if (_isEnabled != value) + { + _isEnabled = value; + OnPropertyChanged(); + EnabledChangedCallback?.Invoke(this); + } + } + } + + public Action EnabledChangedCallback { get; set; } = null; + + 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/Settings.UI/ViewModels/Flyout/FlyoutViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/Flyout/FlyoutViewModel.cs new file mode 100644 index 0000000000..c781535afb --- /dev/null +++ b/src/settings-ui/Settings.UI/ViewModels/Flyout/FlyoutViewModel.cs @@ -0,0 +1,38 @@ +// 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.Timers; + +namespace Microsoft.PowerToys.Settings.UI.ViewModels.Flyout +{ + public class FlyoutViewModel + { + public bool CanHide { get; set; } + + private Timer hideTimer; + + public FlyoutViewModel() + { + CanHide = true; + hideTimer = new Timer(); + hideTimer.Elapsed += HideTimer_Elapsed; + hideTimer.Interval = 1000; + hideTimer.Enabled = false; + } + + private void HideTimer_Elapsed(object sender, ElapsedEventArgs e) + { + CanHide = true; + hideTimer.Stop(); + } + + internal void DisableHiding() + { + CanHide = false; + hideTimer.Stop(); + hideTimer.Start(); + } + } +} diff --git a/src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs new file mode 100644 index 0000000000..66490cea04 --- /dev/null +++ b/src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs @@ -0,0 +1,166 @@ +// 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 Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.PowerToys.Settings.UI.Library.Helpers; +using Microsoft.PowerToys.Settings.UI.Library.Interfaces; +using Windows.ApplicationModel.Resources; + +namespace Microsoft.PowerToys.Settings.UI.ViewModels +{ + public class LauncherViewModel : Observable + { + public bool IsUpdateAvailable { get; set; } + + public ObservableCollection FlyoutMenuItems { get; set; } + + private GeneralSettings generalSettingsConfig; + private UpdatingSettings updatingSettingsConfig; + private ISettingsRepository _settingsRepository; + + private Func SendIPCMessage { get; } + + public LauncherViewModel(ISettingsRepository settingsRepository, Func ipcMSGCallBackFunc) + { + _settingsRepository = settingsRepository; + generalSettingsConfig = settingsRepository.SettingsConfig; + generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + + // set the callback functions value to hangle outgoing IPC message. + SendIPCMessage = ipcMSGCallBackFunc; + ResourceLoader resourceLoader = ResourceLoader.GetForViewIndependentUse(); + FlyoutMenuItems = new ObservableCollection(); + if (GPOWrapper.GetConfiguredColorPickerEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("ColorPicker/ModuleTitle"), + Tag = "ColorPicker", + Visible = generalSettingsConfig.Enabled.ColorPicker, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsColorPicker.png", + }); + } + + if (GPOWrapper.GetConfiguredFancyZonesEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("FZEditorString"), + Tag = "FancyZones", + Visible = generalSettingsConfig.Enabled.FancyZones, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsFancyZones.png", + }); + } + + if (GPOWrapper.GetConfiguredHostsFileEditorEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("Hosts/ModuleTitle"), + Tag = "Hosts", + Visible = generalSettingsConfig.Enabled.Hosts, + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsHosts.png", + }); + } + + if (GPOWrapper.GetConfiguredPowerLauncherEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("PowerLauncher/ModuleTitle"), + Tag = "PowerLauncher", + Visible = generalSettingsConfig.Enabled.PowerLauncher, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerToysRun.png", + }); + } + + if (GPOWrapper.GetConfiguredTextExtractorEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("TextExtractor/ModuleTitle"), + Tag = "PowerOCR", + Visible = generalSettingsConfig.Enabled.PowerOCR, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerOcr.png", + }); + } + + if (GPOWrapper.GetConfiguredScreenRulerEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("MeasureTool/ModuleTitle"), + Tag = "MeasureTool", + Visible = generalSettingsConfig.Enabled.MeasureTool, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsScreenRuler.png", + }); + } + + if (GPOWrapper.GetConfiguredShortcutGuideEnabledValue() != GpoRuleConfigured.Disabled) + { + FlyoutMenuItems.Add(new FlyoutMenuItem() + { + Label = resourceLoader.GetString("ShortcutGuide/ModuleTitle"), + Tag = "ShortcutGuide", + Visible = generalSettingsConfig.Enabled.ShortcutGuide, + ToolTip = SettingsRepository.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenShortcutGuide.ToString(), + Icon = "ms-appx:///Assets/FluentIcons/FluentIconsShortcutGuide.png", + }); + } + + if (updatingSettingsConfig == null) + { + updatingSettingsConfig = new UpdatingSettings(); + } + + updatingSettingsConfig = UpdatingSettings.LoadSettings(); + + if (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload) + { + IsUpdateAvailable = true; + } + else + { + IsUpdateAvailable = false; + } + } + + private void ModuleEnabledChanged() + { + generalSettingsConfig = _settingsRepository.SettingsConfig; + generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + foreach (FlyoutMenuItem item in FlyoutMenuItems) + { + switch (item.Tag) + { + case "ColorPicker": item.Visible = generalSettingsConfig.Enabled.ColorPicker; break; + case "FancyZones": item.Visible = generalSettingsConfig.Enabled.FancyZones; break; + case "Hosts": item.Visible = generalSettingsConfig.Enabled.Hosts; break; + case "PowerLauncher": item.Visible = generalSettingsConfig.Enabled.PowerLauncher; break; + case "PowerOCR": item.Visible = generalSettingsConfig.Enabled.PowerOCR; break; + case "MeasureTool": item.Visible = generalSettingsConfig.Enabled.MeasureTool; break; + case "ShortcutGuide": item.Visible = generalSettingsConfig.Enabled.ShortcutGuide; break; + } + } + } + + internal void StartBugReport() + { + SendIPCMessage("{\"bugreport\": 0 }"); + } + + internal void KillRunner() + { + SendIPCMessage("{\"killrunner\": 0 }"); + } + } +} diff --git a/src/settings-ui/Settings.UI/ViewModels/HostsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/HostsViewModel.cs index 16b5e00054..bed5dc565b 100644 --- a/src/settings-ui/Settings.UI/ViewModels/HostsViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/HostsViewModel.cs @@ -109,6 +109,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings = moduleSettingsRepository.SettingsConfig; SendConfigMSG = ipcMSGCallBackFunc; _isElevated = isElevated; + InitializeEnabledValue(); + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredHostsFileEditorEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -139,5 +144,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels OnPropertyChanged(propertyName); SettingsUtils.SaveSettings(Settings.ToJsonString(), HostsSettings.ModuleName); } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/ImageResizerViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ImageResizerViewModel.cs index 9e4a764e53..ed9432c0c5 100644 --- a/src/settings-ui/Settings.UI/ViewModels/ImageResizerViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/ImageResizerViewModel.cs @@ -59,17 +59,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels // set the callback functions value to hangle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredImageResizerEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.ImageResizer; - } + InitializeEnabledValue(); _advancedSizes = Settings.Properties.ImageresizerSizes.Value; _jpegQualityLevel = Settings.Properties.ImageresizerJpegQualityLevel.Value; @@ -88,6 +78,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredImageResizerEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.ImageResizer; + } + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; @@ -420,5 +425,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels return $"{namePrefix} {++newSizeCounter}"; } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs index da2e8037da..a12e5cfdfb 100644 --- a/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs @@ -63,17 +63,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredKeyboardManagerEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.KeyboardManager; - } + InitializeEnabledValue(); // set the callback functions value to hangle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; @@ -111,6 +101,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredKeyboardManagerEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.KeyboardManager; + } + } + public bool Enabled { get @@ -277,6 +282,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels OnPropertyChanged(nameof(RemapShortcuts)); } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(Enabled)); + } + public bool LoadProfile() { var success = true; diff --git a/src/settings-ui/Settings.UI/ViewModels/MeasureToolViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MeasureToolViewModel.cs index cd18565128..90af903553 100644 --- a/src/settings-ui/Settings.UI/ViewModels/MeasureToolViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/MeasureToolViewModel.cs @@ -36,6 +36,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; + InitializeEnabledValue(); + + if (measureToolSettingsRepository == null) + { + throw new ArgumentNullException(nameof(measureToolSettingsRepository)); + } + + Settings = measureToolSettingsRepository.SettingsConfig; + + SendConfigMSG = ipcMSGCallBackFunc; + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredScreenRulerEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -47,15 +61,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isEnabled = GeneralSettingsConfig.Enabled.MeasureTool; } - - if (measureToolSettingsRepository == null) - { - throw new ArgumentNullException(nameof(measureToolSettingsRepository)); - } - - Settings = measureToolSettingsRepository.SettingsConfig; - - SendConfigMSG = ipcMSGCallBackFunc; } public bool IsEnabled @@ -230,6 +235,13 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SettingsUtils.SaveSettings(Settings.ToJsonString(), MeasureToolSettings.ModuleName); } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + OnPropertyChanged(nameof(ShowContinuousCaptureWarning)); + } + public bool ShowContinuousCaptureWarning { get => IsEnabled && ContinuousCapture; diff --git a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs index 88556b3384..a33755de82 100644 --- a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs @@ -35,41 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; - _findMyMouseEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredFindMyMouseEnabledValue(); - if (_findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _findMyMouseEnabledStateIsGPOConfigured = true; - _isFindMyMouseEnabled = _findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isFindMyMouseEnabled = GeneralSettingsConfig.Enabled.FindMyMouse; - } - - _highlighterEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredMouseHighlighterEnabledValue(); - if (_highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _highlighterEnabledStateIsGPOConfigured = true; - _isMouseHighlighterEnabled = _highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isMouseHighlighterEnabled = GeneralSettingsConfig.Enabled.MouseHighlighter; - } - - _mousePointerCrosshairsEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue(); - if (_mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _mousePointerCrosshairsEnabledStateIsGPOConfigured = true; - _isMousePointerCrosshairsEnabled = _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isMousePointerCrosshairsEnabled = GeneralSettingsConfig.Enabled.MousePointerCrosshairs; - } + InitializeEnabledValues(); // To obtain the find my mouse settings, if the file exists. // If not, to create a file with the default settings and to return the default configurations. @@ -134,6 +100,45 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SendConfigMSG = ipcMSGCallBackFunc; } + private void InitializeEnabledValues() + { + _findMyMouseEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredFindMyMouseEnabledValue(); + if (_findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _findMyMouseEnabledStateIsGPOConfigured = true; + _isFindMyMouseEnabled = _findMyMouseEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isFindMyMouseEnabled = GeneralSettingsConfig.Enabled.FindMyMouse; + } + + _highlighterEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredMouseHighlighterEnabledValue(); + if (_highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _highlighterEnabledStateIsGPOConfigured = true; + _isMouseHighlighterEnabled = _highlighterEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isMouseHighlighterEnabled = GeneralSettingsConfig.Enabled.MouseHighlighter; + } + + _mousePointerCrosshairsEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue(); + if (_mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _mousePointerCrosshairsEnabledStateIsGPOConfigured = true; + _isMousePointerCrosshairsEnabled = _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isMousePointerCrosshairsEnabled = GeneralSettingsConfig.Enabled.MousePointerCrosshairs; + } + } + public bool IsFindMyMouseEnabled { get => _isFindMyMouseEnabled; @@ -693,6 +698,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SettingsUtils.SaveSettings(MousePointerCrosshairsSettingsConfig.ToJsonString(), MousePointerCrosshairsSettings.ModuleName); } + public void RefreshEnabledState() + { + InitializeEnabledValues(); + OnPropertyChanged(nameof(IsFindMyMouseEnabled)); + OnPropertyChanged(nameof(IsMouseHighlighterEnabled)); + OnPropertyChanged(nameof(IsMousePointerCrosshairsEnabled)); + } + private Func SendConfigMSG { get; } private GpoRuleConfigured _findMyMouseEnabledGpoRuleConfiguration; diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs index 2596e5952d..a46fe408d5 100644 --- a/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs @@ -80,17 +80,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils)); GeneralSettingsConfig = settingsRepository.SettingsConfig; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQuickAccentEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.PowerAccent; - } + InitializeEnabledValue(); if (_settingsUtils.SettingsExists(PowerAccentSettings.ModuleName)) { @@ -113,6 +103,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SendConfigMSG = ipcMSGCallBackFunc; } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQuickAccentEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.PowerAccent; + } + } + public bool IsEnabled { get => _isEnabled; @@ -308,6 +313,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerLauncherViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerLauncherViewModel.cs index 051cfee6eb..fcc08dc904 100644 --- a/src/settings-ui/Settings.UI/ViewModels/PowerLauncherViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/PowerLauncherViewModel.cs @@ -63,17 +63,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels GeneralSettingsConfig = settingsRepository.SettingsConfig; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredPowerLauncherEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.PowerLauncher; - } + InitializeEnabledValue(); // set the callback functions value to hangle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; @@ -118,6 +108,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SearchPluginsCommand = new RelayCommand(SearchPlugins); } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredPowerLauncherEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.PowerLauncher; + } + } + private void OnPluginInfoChange(object sender, PropertyChangedEventArgs e) { if ( @@ -175,6 +180,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(EnablePowerLauncher)); + OnPropertyChanged(nameof(ShowAllPluginsDisabledWarning)); + OnPropertyChanged(nameof(ShowPluginsLoadingMessage)); + } + public bool IsEnabledGpoConfigured { get => _enabledStateIsGPOConfigured; diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerOcrViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerOcrViewModel.cs index 5b487a059c..7998a3c1e7 100644 --- a/src/settings-ui/Settings.UI/ViewModels/PowerOcrViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/PowerOcrViewModel.cs @@ -95,6 +95,19 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _powerOcrSettings = powerOcrsettingsRepository.SettingsConfig; + InitializeEnabledValue(); + + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + + _delayedTimer = new Timer(); + _delayedTimer.Interval = SaveSettingsDelayInMs; + _delayedTimer.Elapsed += DelayedTimer_Tick; + _delayedTimer.AutoReset = false; + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredTextExtractorEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -106,14 +119,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { _isEnabled = GeneralSettingsConfig.Enabled.PowerOCR; } - - // set the callback functions value to hangle outgoing IPC message. - SendConfigMSG = ipcMSGCallBackFunc; - - _delayedTimer = new Timer(); - _delayedTimer.Interval = SaveSettingsDelayInMs; - _delayedTimer.Elapsed += DelayedTimer_Tick; - _delayedTimer.AutoReset = false; } public bool IsEnabled @@ -237,6 +242,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels JsonSerializer.Serialize(_powerOcrSettings))); } + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } + protected virtual void Dispose(bool disposing) { if (!disposedValue) diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerRenameViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerRenameViewModel.cs index 04252afbd6..039ee3e410 100644 --- a/src/settings-ui/Settings.UI/ViewModels/PowerRenameViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/PowerRenameViewModel.cs @@ -69,6 +69,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _autoComplete = Settings.Properties.MRUEnabled.Value; _powerRenameUseBoostLib = Settings.Properties.UseBoostLib.Value; + InitializeEnabledValue(); + } + + private void InitializeEnabledValue() + { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredPowerRenameEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { @@ -260,5 +265,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SendConfigMSG(ipcMessage.ToJsonString()); } } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + OnPropertyChanged(nameof(GlobalAndMruEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs index 10e1398850..d21142b5da 100644 --- a/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Microsoft.PowerToys.Settings.UI.Helpers; +using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Services; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; diff --git a/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs index 43c6091cac..b23800d294 100644 --- a/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs @@ -53,17 +53,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels // set the callback functions value to hangle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredShortcutGuideEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.ShortcutGuide; - } + InitializeEnabledValue(); _useLegacyPressWinKeyBehavior = Settings.Properties.UseLegacyPressWinKeyBehavior.Value; _pressTimeForGlobalWindowsShortcuts = Settings.Properties.PressTimeForGlobalWindowsShortcuts.Value; @@ -79,6 +69,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredShortcutGuideEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.ShortcutGuide; + } + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; @@ -267,5 +272,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SendConfigMSG(ipcMessage.ToJsonString()); SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName); } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } } } diff --git a/src/settings-ui/Settings.UI/ViewModels/VideoConferenceViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/VideoConferenceViewModel.cs index acc33ea579..c2bd3eb9af 100644 --- a/src/settings-ui/Settings.UI/ViewModels/VideoConferenceViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/VideoConferenceViewModel.cs @@ -92,17 +92,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _selectedMicrophoneIndex = MicrophoneNames.FindIndex(name => name == Settings.Properties.SelectedMicrophone.Value); } - _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredVideoConferenceMuteEnabledValue(); - if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) - { - // Get the enabled state from GPO. - _enabledStateIsGPOConfigured = true; - _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; - } - else - { - _isEnabled = GeneralSettingsConfig.Enabled.VideoConference; - } + InitializeEnabledValue(); _cameraAndMicrophoneMuteHotkey = Settings.Properties.MuteCameraAndMicrophoneHotkey.Value; _microphoneMuteHotkey = Settings.Properties.MuteMicrophoneHotkey.Value; @@ -163,6 +153,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + private void InitializeEnabledValue() + { + _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredVideoConferenceMuteEnabledValue(); + if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) + { + // Get the enabled state from GPO. + _enabledStateIsGPOConfigured = true; + _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; + } + else + { + _isEnabled = GeneralSettingsConfig.Enabled.VideoConference; + } + } + private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; @@ -473,6 +478,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels ModuleName, JsonSerializer.Serialize(Settings))); } + + public void RefreshEnabledState() + { + InitializeEnabledValue(); + OnPropertyChanged(nameof(IsEnabled)); + } } [ComImport] diff --git a/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml.cs b/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml.cs index 36d1cb9e25..b38fffc59e 100644 --- a/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class AlwaysOnTopPage : Page + public sealed partial class AlwaysOnTopPage : Page, IRefreshablePage { private AlwaysOnTopViewModel ViewModel { get; set; } @@ -19,5 +20,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views DataContext = ViewModel; InitializeComponent(); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/AwakePage.xaml.cs b/src/settings-ui/Settings.UI/Views/AwakePage.xaml.cs index cbcdb40d15..ec3abd4806 100644 --- a/src/settings-ui/Settings.UI/Views/AwakePage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/AwakePage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class AwakePage : Page + public sealed partial class AwakePage : Page, IRefreshablePage { private AwakeViewModel ViewModel { get; set; } @@ -19,5 +20,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views DataContext = ViewModel; InitializeComponent(); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/ColorPickerPage.xaml.cs b/src/settings-ui/Settings.UI/Views/ColorPickerPage.xaml.cs index aff159f9bf..f8b55efdcf 100644 --- a/src/settings-ui/Settings.UI/Views/ColorPickerPage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/ColorPickerPage.xaml.cs @@ -14,7 +14,7 @@ using Windows.ApplicationModel.Resources; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class ColorPickerPage : Page + public sealed partial class ColorPickerPage : Page, IRefreshablePage { public ColorPickerViewModel ViewModel { get; set; } @@ -157,5 +157,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views { ColorFormatDialog.IsPrimaryButtonEnabled = ViewModel.SetValidity(ColorFormatDialog.DataContext as ColorFormatModel, ColorFormatDialog.Tag as string); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml.cs b/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml.cs index 0165b025a2..c224c42683 100644 --- a/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/FancyZonesPage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class FancyZonesPage : Page + public sealed partial class FancyZonesPage : Page, IRefreshablePage { private FancyZonesViewModel ViewModel { get; set; } @@ -24,5 +25,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views { Helpers.StartProcessHelper.Start(Helpers.StartProcessHelper.ColorsSettings); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/FileLocksmithPage.xaml.cs b/src/settings-ui/Settings.UI/Views/FileLocksmithPage.xaml.cs index 5a191ce9ff..2481580213 100644 --- a/src/settings-ui/Settings.UI/Views/FileLocksmithPage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/FileLocksmithPage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class FileLocksmithPage : Page + public sealed partial class FileLocksmithPage : Page, IRefreshablePage { private FileLocksmithViewModel ViewModel { get; set; } @@ -19,5 +20,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views DataContext = ViewModel; InitializeComponent(); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/HostsPage.xaml b/src/settings-ui/Settings.UI/Views/HostsPage.xaml index 88476a47d2..bb54a4b1a3 100644 --- a/src/settings-ui/Settings.UI/Views/HostsPage.xaml +++ b/src/settings-ui/Settings.UI/Views/HostsPage.xaml @@ -9,18 +9,14 @@ xmlns:ui="using:CommunityToolkit.WinUI.UI" mc:Ignorable="d"> - + - + - + - + - - + + - - - + + + @@ -78,9 +58,7 @@ - + diff --git a/src/settings-ui/Settings.UI/Views/HostsPage.xaml.cs b/src/settings-ui/Settings.UI/Views/HostsPage.xaml.cs index 9a621f2d5b..b74f03df44 100644 --- a/src/settings-ui/Settings.UI/Views/HostsPage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/HostsPage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class HostsPage : Page + public sealed partial class HostsPage : Page, IRefreshablePage { private HostsViewModel ViewModel { get; } @@ -18,5 +19,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views var settingsUtils = new SettingsUtils(); ViewModel = new HostsViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/ImageResizerPage.xaml b/src/settings-ui/Settings.UI/Views/ImageResizerPage.xaml index 01ab223005..53522cf987 100644 --- a/src/settings-ui/Settings.UI/Views/ImageResizerPage.xaml +++ b/src/settings-ui/Settings.UI/Views/ImageResizerPage.xaml @@ -21,18 +21,14 @@ FalseValue="1" TrueValue="0" /> - + - + - - + + public static IPCMessageCallback CheckForUpdatesMsgCallback { get; set; } + /// + /// Gets or sets callback function for opening main window + /// + public static MainOpeningCallback OpenMainWindowCallback { get; set; } + + /// + /// Gets or sets callback function for updating the general settings + /// + public static UpdatingGeneralSettingsCallback UpdateGeneralSettingsCallback { get; set; } + /// /// Gets or sets callback function for opening oobe window /// public static OobeOpeningCallback OpenOobeWindowCallback { get; set; } + /// + /// Gets or sets callback function for opening flyout window + /// + public static FlyoutOpeningCallback OpenFlyoutCallback { get; set; } + + /// + /// Gets or sets callback function for disabling hide of flyout window + /// + public static DisablingFlyoutHidingCallback DisableFlyoutHidingCallback { get; set; } + /// /// Gets view model. /// @@ -82,7 +122,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views DataContext = ViewModel; ShellHandler = this; ViewModel.Initialize(shellFrame, navigationView, KeyboardAccelerators); - shellFrame.Navigate(typeof(GeneralPage)); + + // NL moved navigation to general page to the moment when the window is first activated (to not make flyout window disappear) + // shellFrame.Navigate(typeof(GeneralPage)); + IPCResponseHandleList.Add(ReceiveMessage); } public static int SendDefaultIPCMessage(string msg) @@ -131,6 +174,24 @@ namespace Microsoft.PowerToys.Settings.UI.Views CheckForUpdatesMsgCallback = implementation; } + /// + /// Set main window opening callback function + /// + /// delegate function implementation. + public static void SetOpenMainWindowCallback(MainOpeningCallback implementation) + { + OpenMainWindowCallback = implementation; + } + + /// + /// Set updating the general settings callback function + /// + /// delegate function implementation. + public static void SetUpdatingGeneralSettingsCallback(UpdatingGeneralSettingsCallback implementation) + { + UpdateGeneralSettingsCallback = implementation; + } + /// /// Set oobe opening callback function /// @@ -140,6 +201,24 @@ namespace Microsoft.PowerToys.Settings.UI.Views OpenOobeWindowCallback = implementation; } + /// + /// Set flyout opening callback function + /// + /// delegate function implementation. + public static void SetOpenFlyoutCallback(FlyoutOpeningCallback implementation) + { + OpenFlyoutCallback = implementation; + } + + /// + /// Set disable flyout hiding callback function + /// + /// delegate function implementation. + public static void SetDisableFlyoutHidingCallback(DisablingFlyoutHidingCallback implementation) + { + DisableFlyoutHidingCallback = implementation; + } + public static void SetElevationStatus(bool isElevated) { IsElevated = isElevated; @@ -160,6 +239,16 @@ namespace Microsoft.PowerToys.Settings.UI.Views shellFrame.Navigate(typeof(GeneralPage)); } + // Tell the current page view model to update + public void SignalGeneralDataUpdate() + { + IRefreshablePage currentPage = shellFrame?.Content as IRefreshablePage; + if (currentPage != null) + { + currentPage.RefreshEnabledState(); + } + } + private void OobeButton_Click(object sender, RoutedEventArgs e) { OpenOobeWindowCallback(); @@ -236,5 +325,28 @@ namespace Microsoft.PowerToys.Settings.UI.Views NavigationService.Navigate(pageType); } } + + private void ReceiveMessage(JsonObject json) + { + if (json != null) + { + if (json.ToString().StartsWith("{\"ShowYourself\":")) + { + if (json.ToString().EndsWith("\"flyout\"}")) + { + OpenFlyoutCallback(); + } + else if (json.ToString().EndsWith("\"main_page\"}")) + { + OpenMainWindowCallback(); + } + } + } + } + + internal static void EnsurePageIsSelected() + { + NavigationService.EnsurePageIsSelected(typeof(GeneralPage)); + } } } diff --git a/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml.cs b/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml.cs index 403ee8d6ae..750007595a 100644 --- a/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml.cs @@ -2,13 +2,14 @@ // 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.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class ShortcutGuidePage : Page + public sealed partial class ShortcutGuidePage : Page, IRefreshablePage { private ShortcutGuideViewModel ViewModel { get; set; } @@ -25,5 +26,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views { Helpers.StartProcessHelper.Start(Helpers.StartProcessHelper.ColorsSettings); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } } diff --git a/src/settings-ui/Settings.UI/Views/VideoConference.xaml.cs b/src/settings-ui/Settings.UI/Views/VideoConference.xaml.cs index b45ac61aed..1a5d80a035 100644 --- a/src/settings-ui/Settings.UI/Views/VideoConference.xaml.cs +++ b/src/settings-ui/Settings.UI/Views/VideoConference.xaml.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; +using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml.Controls; @@ -12,7 +13,7 @@ using Windows.Storage.Pickers; namespace Microsoft.PowerToys.Settings.UI.Views { - public sealed partial class VideoConferencePage : Page + public sealed partial class VideoConferencePage : Page, IRefreshablePage { private VideoConferenceViewModel ViewModel { get; set; } @@ -43,5 +44,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views DataContext = ViewModel; InitializeComponent(); } + + public void RefreshEnabledState() + { + ViewModel.RefreshEnabledState(); + } } }