From f773604dec77c3c8cdd65c4da1b2379ace543e2d Mon Sep 17 00:00:00 2001 From: Divyansh Srivastava Date: Wed, 22 Jul 2020 12:48:42 -0700 Subject: [PATCH] Added functionality for left/right key navigation (#5067) * Added functionality for left/right key navigation * Update Behviour of left/right navigation * Code cleanup * Null check for results VM * Added tests for results view model * Update test namings --- .../launcher/PowerLauncher/MainWindow.xaml.cs | 19 ++ .../PowerLauncher/ViewModel/MainViewModel.cs | 12 ++ .../ViewModel/ResultViewModel.cs | 2 +- .../ViewModel/ResultsViewModel.cs | 35 +++- .../launcher/Wox.Core/Plugin/PluginManager.cs | 2 +- .../launcher/Wox.Test/ResultsViewModelTest.cs | 172 ++++++++++++++++++ 6 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 src/modules/launcher/Wox.Test/ResultsViewModelTest.cs diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs index 2dab03ada5..e7409ba171 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs @@ -239,6 +239,25 @@ namespace PowerLauncher UpdateTextBoxToSelectedItem(); e.Handled = true; } + else if (e.Key == Key.Right) + { + if(SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) + { + _viewModel.SelectNextContextMenuItemCommand.Execute(null); + e.Handled = true; + } + } + else if (e.Key == Key.Left) + { + if (SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) + { + if(_viewModel.Results != null && _viewModel.Results.IsContextMenuItemSelected()) + { + _viewModel.SelectPreviousContextMenuItemCommand.Execute(null); + e.Handled = true; + } + } + } else if (e.Key == Key.PageDown) { _viewModel.SelectNextPageCommand.Execute(null); diff --git a/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs b/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs index b37d63f60a..d58ed2204f 100644 --- a/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs +++ b/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs @@ -151,6 +151,16 @@ namespace PowerLauncher.ViewModel SelectedResults.SelectPrevTabItem(); }); + SelectNextContextMenuItemCommand = new RelayCommand(_ => + { + SelectedResults.SelectNextContextMenuItem(); + }); + + SelectPreviousContextMenuItemCommand = new RelayCommand(_ => + { + SelectedResults.SelectPreviousContextMenuItem(); + }); + SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); @@ -342,6 +352,8 @@ namespace PowerLauncher.ViewModel public ICommand EscCommand { get; set; } public ICommand SelectNextItemCommand { get; set; } public ICommand SelectPrevItemCommand { get; set; } + public ICommand SelectNextContextMenuItemCommand { get; set; } + public ICommand SelectPreviousContextMenuItemCommand { get; set; } public ICommand SelectNextTabItemCommand { get; set; } public ICommand SelectPrevTabItemCommand { get; set; } diff --git a/src/modules/launcher/PowerLauncher/ViewModel/ResultViewModel.cs b/src/modules/launcher/PowerLauncher/ViewModel/ResultViewModel.cs index fcc2e8912f..b16ceae9b5 100644 --- a/src/modules/launcher/PowerLauncher/ViewModel/ResultViewModel.cs +++ b/src/modules/launcher/PowerLauncher/ViewModel/ResultViewModel.cs @@ -34,7 +34,7 @@ namespace PowerLauncher.ViewModel public int ContextMenuSelectedIndex { get; set; } - const int NoSelectionIndex = -1; + public const int NoSelectionIndex = -1; public ResultViewModel(Result result) { diff --git a/src/modules/launcher/PowerLauncher/ViewModel/ResultsViewModel.cs b/src/modules/launcher/PowerLauncher/ViewModel/ResultsViewModel.cs index 25e191bed8..74228a15eb 100644 --- a/src/modules/launcher/PowerLauncher/ViewModel/ResultsViewModel.cs +++ b/src/modules/launcher/PowerLauncher/ViewModel/ResultsViewModel.cs @@ -180,6 +180,37 @@ namespace PowerLauncher.ViewModel SelectPrevResult(); SelectedItem.SelectLastContextButton(); } + } + + public void SelectNextContextMenuItem() + { + if(SelectedItem != null) + { + if(!SelectedItem.SelectNextContextButton()) + { + SelectedItem.SelectLastContextButton(); + } + } + } + + public void SelectPreviousContextMenuItem() + { + if (SelectedItem != null) + { + SelectedItem.SelectPrevContextButton(); + } + } + + public bool IsContextMenuItemSelected() + { + if (SelectedItem != null && SelectedItem.ContextMenuSelectedIndex != ResultViewModel.NoSelectionIndex) + { + return true; + } + else + { + return false; + } } /// @@ -205,8 +236,8 @@ namespace PowerLauncher.ViewModel Visibility = Visibility.Collapsed; } } - } - + } + private List NewResults(List newRawResults, string resultId) { var results = Results.ToList(); diff --git a/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs b/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs index bf55166309..549039485a 100644 --- a/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs +++ b/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs @@ -17,7 +17,7 @@ namespace Wox.Core.Plugin /// public static class PluginManager { - private static IEnumerable _contextMenuPlugins; + private static IEnumerable _contextMenuPlugins = new List(); /// /// Directories that will hold Wox plugin directory diff --git a/src/modules/launcher/Wox.Test/ResultsViewModelTest.cs b/src/modules/launcher/Wox.Test/ResultsViewModelTest.cs new file mode 100644 index 0000000000..777c8c4ffd --- /dev/null +++ b/src/modules/launcher/Wox.Test/ResultsViewModelTest.cs @@ -0,0 +1,172 @@ +using NUnit.Framework; +using PowerLauncher.ViewModel; +using System; +using System.Collections.Generic; +using System.Text; +using Wox.Core.Plugin; +using Wox.Plugin; + +namespace Wox.Test +{ + [TestFixture] + class ResultsViewModelTest + { + [Test] + public void ContextMenuSelectedIndex_ShouldEqualNoSelectionIndex_WhenInitialized() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + // Assert + Assert.AreEqual(selectedItem.ContextMenuSelectedIndex, ResultViewModel.NoSelectionIndex); + } + + [Test] + public void SelectNextContextMenuItem_IncrementsContextMenuSelectedIndex_WhenCalled() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + + // Assert + Assert.AreEqual(selectedItem.ContextMenuSelectedIndex, 0); + } + + [Test] + public void SelectNextContextMenuItem_DoesnNotIncrementContextMenuSelectedIndex_WhenCalledOnLastItem() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + + // Assert + Assert.AreEqual(selectedItem.ContextMenuSelectedIndex, 0); + } + + [Test] + public void SelectPreviousContextMenuItem_DecrementsContextMenuSelectedIndex_WhenCalled() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu 1" + }); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu 2" + }); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu 3" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + rvm.SelectNextContextMenuItem(); + rvm.SelectNextContextMenuItem(); + rvm.SelectPreviousContextMenuItem(); + + // Assert + Assert.AreEqual(selectedItem.ContextMenuSelectedIndex, 1); + } + + [Test] + public void SelectPreviousContextMenuItem_ResetsContextMenuSelectedIndex_WhenCalledOnFirstItem() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + rvm.SelectPreviousContextMenuItem(); + + // Assert + Assert.AreEqual(selectedItem.ContextMenuSelectedIndex, ResultViewModel.NoSelectionIndex); + } + + [Test] + public void IsContextMenuItemSelected_ReturnsTrue_WhenContextMenuItemIsSelected() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + bool isContextMenuItemSelected = rvm.IsContextMenuItemSelected(); + + // Assert + Assert.IsTrue(isContextMenuItemSelected); + } + + [Test] + public void IsContextMenuItemSelected_ReturnsFalse_WhenContextMenuItemIsNotSelected() + { + // Arrange + ResultsViewModel rvm = new ResultsViewModel(); + Result result = new Result(); + ResultViewModel selectedItem = new ResultViewModel(result); + selectedItem.ContextMenuItems.Add(new ContextMenuItemViewModel() + { + Title = "Dummy Context Menu" + }); + rvm.SelectedItem = selectedItem; + + + // Act + rvm.SelectNextContextMenuItem(); + rvm.SelectPreviousContextMenuItem(); + bool isContextMenuItemSelected = rvm.IsContextMenuItemSelected(); + + // Assert + Assert.IsFalse(isContextMenuItemSelected); + } + } +}