// 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 System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Services; using Windows.System; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; using WinUI = Microsoft.UI.Xaml.Controls; namespace Microsoft.PowerToys.Settings.UI.ViewModels { public class ShellViewModel : Observable { private readonly KeyboardAccelerator altLeftKeyboardAccelerator = BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu); private readonly KeyboardAccelerator backKeyboardAccelerator = BuildKeyboardAccelerator(VirtualKey.GoBack); private bool isBackEnabled; private IList keyboardAccelerators; private WinUI.NavigationView navigationView; private WinUI.NavigationViewItem selected; private ICommand loadedCommand; private ICommand itemInvokedCommand; public bool IsBackEnabled { get { return this.isBackEnabled; } set { this.Set(ref this.isBackEnabled, value); } } public WinUI.NavigationViewItem Selected { get { return this.selected; } set { this.Set(ref this.selected, value); } } public ICommand LoadedCommand => this.loadedCommand ?? (this.loadedCommand = new RelayCommand(this.OnLoaded)); public ICommand ItemInvokedCommand => this.itemInvokedCommand ?? (this.itemInvokedCommand = new RelayCommand(this.OnItemInvoked)); public ShellViewModel() { } public void Initialize(Frame frame, WinUI.NavigationView navigationView, IList keyboardAccelerators) { this.navigationView = navigationView; this.keyboardAccelerators = keyboardAccelerators; NavigationService.Frame = frame; NavigationService.NavigationFailed += this.Frame_NavigationFailed; NavigationService.Navigated += this.Frame_Navigated; this.navigationView.BackRequested += this.OnBackRequested; } private static KeyboardAccelerator BuildKeyboardAccelerator(VirtualKey key, VirtualKeyModifiers? modifiers = null) { var keyboardAccelerator = new KeyboardAccelerator() { Key = key }; if (modifiers.HasValue) { keyboardAccelerator.Modifiers = modifiers.Value; } keyboardAccelerator.Invoked += OnKeyboardAcceleratorInvoked; return keyboardAccelerator; } private static void OnKeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) { var result = NavigationService.GoBack(); args.Handled = result; } private async void OnLoaded() { // Keyboard accelerators are added here to avoid showing 'Alt + left' tooltip on the page. // More info on tracking issue https://github.com/Microsoft/microsoft-ui-xaml/issues/8 this.keyboardAccelerators.Add(this.altLeftKeyboardAccelerator); this.keyboardAccelerators.Add(this.backKeyboardAccelerator); await Task.CompletedTask; } private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args) { var item = this.navigationView.MenuItems .OfType() .First(menuItem => (string)menuItem.Content == (string)args.InvokedItem); var pageType = item.GetValue(NavHelper.NavigateToProperty) as Type; NavigationService.Navigate(pageType); } private void OnBackRequested(WinUI.NavigationView sender, WinUI.NavigationViewBackRequestedEventArgs args) { NavigationService.GoBack(); } private void Frame_NavigationFailed(object sender, NavigationFailedEventArgs e) { throw e.Exception; } private void Frame_Navigated(object sender, NavigationEventArgs e) { this.IsBackEnabled = NavigationService.CanGoBack; this.Selected = this.navigationView.MenuItems .OfType() .FirstOrDefault(menuItem => this.IsMenuItemForPageType(menuItem, e.SourcePageType)); } private bool IsMenuItemForPageType(WinUI.NavigationViewItem menuItem, Type sourcePageType) { var pageType = menuItem.GetValue(NavHelper.NavigateToProperty) as Type; return pageType == sourcePageType; } } }