// 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.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Services; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Navigation; using Windows.System; namespace Microsoft.PowerToys.Settings.UI.ViewModels { public partial 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 NavigationView navigationView; private NavigationViewItem selected; private ICommand loadedCommand; private ICommand itemInvokedCommand; private NavigationViewItem[] _fullListOfNavViewItems; public bool IsBackEnabled { get { return isBackEnabled; } set { Set(ref isBackEnabled, value); } } public NavigationViewItem Selected { get { return selected; } set { Set(ref selected, value); } } public ICommand LoadedCommand => loadedCommand ?? (loadedCommand = new RelayCommand(OnLoaded)); public ICommand ItemInvokedCommand => itemInvokedCommand ?? (itemInvokedCommand = new RelayCommand(OnItemInvoked)); public ShellViewModel() { } public void Initialize(Frame frame, NavigationView navigationView, IList keyboardAccelerators) { this.navigationView = navigationView; this.keyboardAccelerators = keyboardAccelerators; NavigationService.Frame = frame; NavigationService.NavigationFailed += Frame_NavigationFailed; NavigationService.Navigated += Frame_Navigated; this.navigationView.BackRequested += OnBackRequested; var topLevelItems = navigationView.MenuItems.OfType(); _fullListOfNavViewItems = topLevelItems.Union(topLevelItems.SelectMany(menuItem => menuItem.MenuItems.OfType())).ToArray(); } 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 keyboardAccelerators.Add(altLeftKeyboardAccelerator); keyboardAccelerators.Add(backKeyboardAccelerator); await Task.CompletedTask.ConfigureAwait(false); } private void OnItemInvoked(NavigationViewItemInvokedEventArgs args) { var pageType = args.InvokedItemContainer.GetValue(NavHelper.NavigateToProperty) as Type; if (pageType != null) { NavigationService.Navigate(pageType); } } private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) { NavigationService.GoBack(); } private void Frame_NavigationFailed(object sender, NavigationFailedEventArgs e) { throw e.Exception; } private void Frame_Navigated(object sender, NavigationEventArgs e) { IsBackEnabled = NavigationService.CanGoBack; Selected = _fullListOfNavViewItems.FirstOrDefault(menuItem => IsMenuItemForPageType(menuItem, e.SourcePageType)); } private static bool IsMenuItemForPageType(NavigationViewItem menuItem, Type sourcePageType) { var pageType = menuItem.GetValue(NavHelper.NavigateToProperty) as Type; return pageType == sourcePageType; } } }