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 _isBackEnabled; } set { Set(ref _isBackEnabled, value); } } public WinUI.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, WinUI.NavigationView navigationView, IList keyboardAccelerators) { _navigationView = navigationView; _keyboardAccelerators = keyboardAccelerators; NavigationService.Frame = frame; NavigationService.NavigationFailed += Frame_NavigationFailed; NavigationService.Navigated += Frame_Navigated; _navigationView.BackRequested += OnBackRequested; } 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; } private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args) { var item = _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) { IsBackEnabled = NavigationService.CanGoBack; Selected = _navigationView.MenuItems .OfType() .FirstOrDefault(menuItem => IsMenuItemForPageType(menuItem, e.SourcePageType)); } private bool IsMenuItemForPageType(WinUI.NavigationViewItem menuItem, Type sourcePageType) { var pageType = menuItem.GetValue(NavHelper.NavigateToProperty) as Type; return pageType == sourcePageType; } 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; } } }