// 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.Generic; using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Services; using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Automation.Peers; using Microsoft.UI.Xaml.Controls; using Windows.Data.Json; using Windows.System; namespace Microsoft.PowerToys.Settings.UI.Views { /// /// Root page. /// public sealed partial class ShellPage : UserControl { /// /// Declaration for the ipc callback function. /// /// message. public delegate void IPCMessageCallback(string msg); /// /// Declaration for the opening main window callback function. /// public delegate void MainOpeningCallback(Type type); /// /// Declaration for the updating the general settings callback function. /// public delegate bool UpdatingGeneralSettingsCallback(string module, bool isEnabled); /// /// Declaration for the opening oobe window callback function. /// public delegate void OobeOpeningCallback(); /// /// Declaration for the opening flyout window callback function. /// public delegate void FlyoutOpeningCallback(POINT? point); /// /// Declaration for the disabling hide of flyout window callback function. /// public delegate void DisablingFlyoutHidingCallback(); /// /// Gets or sets a shell handler to be used to update contents of the shell dynamically from page within the frame. /// public static ShellPage ShellHandler { get; set; } /// /// Gets or sets iPC default callback function. /// public static IPCMessageCallback DefaultSndMSGCallback { get; set; } /// /// Gets or sets iPC callback function for restart as admin. /// public static IPCMessageCallback SndRestartAsAdminMsgCallback { get; set; } /// /// Gets or sets iPC callback function for checking updates. /// 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. /// public ShellViewModel ViewModel { get; } = new ShellViewModel(); /// /// Gets a collection of functions that handle IPC responses. /// public List> IPCResponseHandleList { get; } = new List>(); public static bool IsElevated { get; set; } public static bool IsUserAnAdmin { get; set; } /// /// Initializes a new instance of the class. /// Shell page constructor. /// public ShellPage() { InitializeComponent(); DataContext = ViewModel; ShellHandler = this; ViewModel.Initialize(shellFrame, navigationView, KeyboardAccelerators); // 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); SetTitleBar(); } public static int SendDefaultIPCMessage(string msg) { DefaultSndMSGCallback?.Invoke(msg); return 0; } public static int SendCheckForUpdatesIPCMessage(string msg) { CheckForUpdatesMsgCallback?.Invoke(msg); return 0; } public static int SendRestartAdminIPCMessage(string msg) { SndRestartAsAdminMsgCallback?.Invoke(msg); return 0; } /// /// Set Default IPC Message callback function. /// /// delegate function implementation. public static void SetDefaultSndMessageCallback(IPCMessageCallback implementation) { DefaultSndMSGCallback = implementation; } /// /// Set restart as admin IPC callback function. /// /// delegate function implementation. public static void SetRestartAdminSndMessageCallback(IPCMessageCallback implementation) { SndRestartAsAdminMsgCallback = implementation; } /// /// Set check for updates IPC callback function. /// /// delegate function implementation. public static void SetCheckForUpdatesMessageCallback(IPCMessageCallback implementation) { 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 /// /// delegate function implementation. public static void SetOpenOobeCallback(OobeOpeningCallback implementation) { 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; } public static void SetIsUserAnAdmin(bool isAdmin) { IsUserAnAdmin = isAdmin; } public static void Navigate(Type type) { NavigationService.Navigate(type); } public void Refresh() { shellFrame.Navigate(typeof(DashboardPage)); } // 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(); } private bool navigationViewInitialStateProcessed; // avoid announcing initial state of the navigation pane. private void NavigationView_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) { if (!navigationViewInitialStateProcessed) { navigationViewInitialStateProcessed = true; return; } var peer = FrameworkElementAutomationPeer.FromElement(sender); if (peer == null) { peer = FrameworkElementAutomationPeer.CreatePeerForElement(sender); } if (AutomationPeer.ListenerExists(AutomationEvents.MenuOpened)) { var loader = Helpers.ResourceLoaderInstance.ResourceLoader; peer.RaiseNotificationEvent( AutomationNotificationKind.ActionCompleted, AutomationNotificationProcessing.ImportantMostRecent, loader.GetString("Shell_NavigationMenu_Announce_Open"), "navigationMenuPaneOpened"); } } private void NavigationView_PaneClosed(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) { if (!navigationViewInitialStateProcessed) { navigationViewInitialStateProcessed = true; return; } var peer = FrameworkElementAutomationPeer.FromElement(sender); if (peer == null) { peer = FrameworkElementAutomationPeer.CreatePeerForElement(sender); } if (AutomationPeer.ListenerExists(AutomationEvents.MenuClosed)) { var loader = Helpers.ResourceLoaderInstance.ResourceLoader; peer.RaiseNotificationEvent( AutomationNotificationKind.ActionCompleted, AutomationNotificationProcessing.ImportantMostRecent, loader.GetString("Shell_NavigationMenu_Announce_Collapse"), "navigationMenuPaneClosed"); } } private void OOBEItem_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { OpenOobeWindowCallback(); } private async void FeedbackItem_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { await Launcher.LaunchUriAsync(new Uri("https://aka.ms/powerToysGiveFeedback")); } private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { NavigationViewItem selectedItem = args.SelectedItem as NavigationViewItem; if (selectedItem != null) { Type pageType = selectedItem.GetValue(NavHelper.NavigateToProperty) as Type; NavigationService.Navigate(pageType); } } private void ReceiveMessage(JsonObject json) { if (json != null) { IJsonValue whatToShowJson; if (json.TryGetValue("ShowYourself", out whatToShowJson)) { if (whatToShowJson.ValueType == JsonValueType.String && whatToShowJson.GetString().Equals("flyout", StringComparison.Ordinal)) { POINT? p = null; IJsonValue flyoutPointX; IJsonValue flyoutPointY; if (json.TryGetValue("x_position", out flyoutPointX) && json.TryGetValue("y_position", out flyoutPointY)) { if (flyoutPointX.ValueType == JsonValueType.Number && flyoutPointY.ValueType == JsonValueType.Number) { int flyout_x = (int)flyoutPointX.GetNumber(); int flyout_y = (int)flyoutPointY.GetNumber(); p = new POINT(flyout_x, flyout_y); } } OpenFlyoutCallback(p); } else if (whatToShowJson.ValueType == JsonValueType.String) { OpenMainWindowCallback(App.GetPage(whatToShowJson.GetString())); } } } } internal static void EnsurePageIsSelected() { NavigationService.EnsurePageIsSelected(typeof(DashboardPage)); } private void SetTitleBar() { var u = App.GetSettingsWindow(); if (u != null) { // A custom title bar is required for full window theme and Mica support. // https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization u.ExtendsContentIntoTitleBar = true; u.SetTitleBar(AppTitleBar); var loader = ResourceLoaderInstance.ResourceLoader; AppTitleBarText.Text = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title"); #if DEBUG DebugMessage.Visibility = Visibility.Visible; #endif } } private void ShellPage_Loaded(object sender, RoutedEventArgs e) { SetTitleBar(); } private void NavigationView_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) { if (args.DisplayMode == NavigationViewDisplayMode.Compact || args.DisplayMode == NavigationViewDisplayMode.Minimal) { PaneToggleBtn.Visibility = Visibility.Visible; AppTitleBar.Margin = new Thickness(48, 0, 0, 0); AppTitleBarText.Margin = new Thickness(12, 0, 0, 0); } else { PaneToggleBtn.Visibility = Visibility.Collapsed; AppTitleBar.Margin = new Thickness(16, 0, 0, 0); AppTitleBarText.Margin = new Thickness(16, 0, 0, 0); } } private void PaneToggleBtn_Click(object sender, RoutedEventArgs e) { navigationView.IsPaneOpen = !navigationView.IsPaneOpen; } } }