/ src / settings-ui / Settings.UI / ViewModels / ShellViewModel.cs
ShellViewModel.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  
  5  using System;
  6  using System.Collections.Generic;
  7  using System.IO;
  8  using System.Linq;
  9  using System.Threading.Tasks;
 10  using System.Windows.Input;
 11  
 12  using Microsoft.PowerToys.Settings.UI.Helpers;
 13  using Microsoft.PowerToys.Settings.UI.Library;
 14  using Microsoft.PowerToys.Settings.UI.Library.Helpers;
 15  using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
 16  using Microsoft.PowerToys.Settings.UI.Services;
 17  using Microsoft.UI.Xaml.Controls;
 18  using Microsoft.UI.Xaml.Input;
 19  using Microsoft.UI.Xaml.Navigation;
 20  using Windows.System;
 21  
 22  namespace Microsoft.PowerToys.Settings.UI.ViewModels
 23  {
 24      public partial class ShellViewModel : Observable
 25      {
 26          private readonly KeyboardAccelerator altLeftKeyboardAccelerator = BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu);
 27  
 28          private readonly KeyboardAccelerator backKeyboardAccelerator = BuildKeyboardAccelerator(VirtualKey.GoBack);
 29  
 30          private bool isBackEnabled;
 31          private bool showCloseMenu;
 32          private IList<KeyboardAccelerator> keyboardAccelerators;
 33          private NavigationView navigationView;
 34          private NavigationViewItem selected;
 35          private NavigationViewItem expanding;
 36          private ICommand loadedCommand;
 37          private ICommand itemInvokedCommand;
 38          private NavigationViewItem[] _fullListOfNavViewItems;
 39          private NavigationViewItem[] _moduleNavViewItems;
 40          private GeneralSettings _generalSettingsConfig;
 41  
 42          public bool IsBackEnabled
 43          {
 44              get => isBackEnabled;
 45              set => Set(ref isBackEnabled, value);
 46          }
 47  
 48          public bool ShowCloseMenu
 49          {
 50              get => showCloseMenu;
 51              set => Set(ref showCloseMenu, value);
 52          }
 53  
 54          public NavigationViewItem Selected
 55          {
 56              get => selected;
 57              set => Set(ref selected, value);
 58          }
 59  
 60          public NavigationViewItem Expanding
 61          {
 62              get { return expanding; }
 63              set { Set(ref expanding, value); }
 64          }
 65  
 66          public NavigationViewItem[] NavItems
 67          {
 68              get { return _moduleNavViewItems; }
 69          }
 70  
 71          public ICommand LoadedCommand => loadedCommand ?? (loadedCommand = new RelayCommand(OnLoaded));
 72  
 73          public ICommand ItemInvokedCommand => itemInvokedCommand ?? (itemInvokedCommand = new RelayCommand<NavigationViewItemInvokedEventArgs>(OnItemInvoked));
 74  
 75          public ShellViewModel(ISettingsRepository<GeneralSettings> settingsRepository)
 76          {
 77              _generalSettingsConfig = settingsRepository.SettingsConfig;
 78              ShowCloseMenu = !_generalSettingsConfig.ShowSysTrayIcon;
 79          }
 80  
 81          public void Initialize(Frame frame, NavigationView navigationView, IList<KeyboardAccelerator> keyboardAccelerators)
 82          {
 83              this.navigationView = navigationView;
 84              this.keyboardAccelerators = keyboardAccelerators;
 85              NavigationService.Frame = frame;
 86              NavigationService.NavigationFailed += Frame_NavigationFailed;
 87              NavigationService.Navigated += Frame_Navigated;
 88              this.navigationView.BackRequested += OnBackRequested;
 89              var topLevelItems = navigationView.MenuItems.OfType<NavigationViewItem>();
 90              _moduleNavViewItems = topLevelItems.SelectMany(menuItem => menuItem.MenuItems.OfType<NavigationViewItem>()).ToArray();
 91              _fullListOfNavViewItems = topLevelItems.Union(_moduleNavViewItems).ToArray();
 92          }
 93  
 94          private static KeyboardAccelerator BuildKeyboardAccelerator(VirtualKey key, VirtualKeyModifiers? modifiers = null)
 95          {
 96              var keyboardAccelerator = new KeyboardAccelerator() { Key = key };
 97              if (modifiers.HasValue)
 98              {
 99                  keyboardAccelerator.Modifiers = modifiers.Value;
100              }
101  
102              keyboardAccelerator.Invoked += OnKeyboardAcceleratorInvoked;
103              return keyboardAccelerator;
104          }
105  
106          private static void OnKeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
107          {
108              var result = NavigationService.GoBack();
109              args.Handled = result;
110          }
111  
112          private async void OnLoaded()
113          {
114              // Keyboard accelerators are added here to avoid showing 'Alt + left' tooltip on the page.
115              // More info on tracking issue https://github.com/Microsoft/microsoft-ui-xaml/issues/8
116              keyboardAccelerators.Add(altLeftKeyboardAccelerator);
117              keyboardAccelerators.Add(backKeyboardAccelerator);
118              await Task.CompletedTask.ConfigureAwait(false);
119          }
120  
121          private void OnItemInvoked(NavigationViewItemInvokedEventArgs args)
122          {
123              var pageType = args.InvokedItemContainer.GetValue(NavHelper.NavigateToProperty) as Type;
124  
125              if (pageType != null)
126              {
127                  NavigationService.Navigate(pageType);
128              }
129          }
130  
131          private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
132          {
133              NavigationService.GoBack();
134          }
135  
136          private void Frame_NavigationFailed(object sender, NavigationFailedEventArgs e)
137          {
138              throw e.Exception;
139          }
140  
141          private void Frame_Navigated(object sender, NavigationEventArgs e)
142          {
143              IsBackEnabled = NavigationService.CanGoBack;
144              Selected = _fullListOfNavViewItems.FirstOrDefault(menuItem => IsMenuItemForPageType(menuItem, e.SourcePageType));
145          }
146  
147          private static bool IsMenuItemForPageType(NavigationViewItem menuItem, Type sourcePageType)
148          {
149              var pageType = menuItem.GetValue(NavHelper.NavigateToProperty) as Type;
150              return pageType == sourcePageType;
151          }
152      }
153  }