From 7dabcc00ed4aa40fbcfb5b4680c4a3fb1cdae0a8 Mon Sep 17 00:00:00 2001 From: Divyansh Srivastava Date: Thu, 2 Jul 2020 18:29:39 -0700 Subject: [PATCH] Added fix to update text on navigation using up/down arrow (#4626) * Added fix to update text on navigation using up/down arrow * Fix incorrect alignment with ghost text * Added tests --- .../launcher/PowerLauncher/MainWindow.xaml.cs | 57 +++-- .../launcher/Wox.Test/MainViewModelTest.cs | 211 ++++++++++++++++++ .../launcher/Wox/ViewModel/MainViewModel.cs | 34 +++ 3 files changed, 272 insertions(+), 30 deletions(-) create mode 100644 src/modules/launcher/Wox.Test/MainViewModelTest.cs diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs index 851f246aa7..8d1177b3d9 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs @@ -110,22 +110,31 @@ namespace PowerLauncher private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (Visibility == System.Windows.Visibility.Visible) + if(e.PropertyName == nameof(MainViewModel.MainWindowVisibility)) { - // Not called on first launch - // Additionally called when deactivated by clicking on screen - UpdatePosition(); - BringProcessToForeground(); - - if (!_viewModel.LastQuerySelected) + if (Visibility == System.Windows.Visibility.Visible) { - _viewModel.LastQuerySelected = true; + // Not called on first launch + // Additionally called when deactivated by clicking on screen + UpdatePosition(); + BringProcessToForeground(); + + if (!_viewModel.LastQuerySelected) + { + _viewModel.LastQuerySelected = true; + } } - } + } else if (e.PropertyName == nameof(MainViewModel.SystemQueryText)) { this._isTextSetProgrammatically = true; - SearchBox.QueryTextBox.Text = _viewModel.SystemQueryText; + if (_viewModel.Results != null) + { + SearchBox.QueryTextBox.Text = MainViewModel.GetSearchText( + _viewModel.Results.SelectedIndex, + _viewModel.SystemQueryText, + _viewModel.QueryText); + } } } @@ -261,32 +270,20 @@ namespace PowerLauncher } // To populate the AutoCompleteTextBox as soon as the selection is changed or set. - // Setting it here instead of when the text is changed as there is a delay in executing the query and populating the result - SearchBox.AutoCompleteTextBlock.Text = ListView_FirstItem(_viewModel.QueryText); + // Setting it here instead of when the text is changed as there is a delay in executing the query and populating the result + if (_viewModel.Results != null) + { + SearchBox.AutoCompleteTextBlock.Text = MainViewModel.GetAutoCompleteText( + _viewModel.Results.SelectedIndex, + _viewModel.Results.SelectedItem?.ToString(), + _viewModel.QueryText); + } } private const int millisecondsToWait = 100; private static DateTime s_lastTimeOfTyping; private bool disposedValue = false; - private string ListView_FirstItem(String input) - { - if (!string.IsNullOrEmpty(input)) - { - string selectedItem = _viewModel.Results?.SelectedItem?.ToString(); - int selectedIndex = _viewModel.Results.SelectedIndex; - if (selectedItem != null && selectedIndex == 0) - { - if (selectedItem.IndexOf(input, StringComparison.InvariantCultureIgnoreCase) == 0) - { - // Use the same case as the input query for the matched portion of the string - return input + selectedItem.Substring(input.Length); - } - } - } - - return string.Empty; - } private void QueryTextBox_TextChanged(object sender, TextChangedEventArgs e) { if (_isTextSetProgrammatically) diff --git a/src/modules/launcher/Wox.Test/MainViewModelTest.cs b/src/modules/launcher/Wox.Test/MainViewModelTest.cs new file mode 100644 index 0000000000..a299d8ca13 --- /dev/null +++ b/src/modules/launcher/Wox.Test/MainViewModelTest.cs @@ -0,0 +1,211 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; +using Wox.Plugin; +using Wox.ViewModel; + +namespace Wox.Test +{ + [TestFixture] + class MainViewModelTest + { + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenInputIsNull() + { + // Arrange + int index = 0; + string input = null; + String query = "M"; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenInputIsEmpty() + { + // Arrange + int index = 0; + string input = string.Empty; + String query = "M"; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenQueryIsNull() + { + // Arrange + int index = 0; + string input = "M"; + String query = null; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenQueryIsEmpty() + { + // Arrange + int index = 0; + string input = "M"; + String query = string.Empty; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenIndexIsNonZero() + { + // Arrange + int index = 2; + string input = "Visual"; + String query = "Vis"; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsMatchingString_WhenIndexIsZeroAndMatch() + { + // Arrange + int index = 0; + string input = "VISUAL"; + String query = "VIs"; + string ExpectedAutoCompleteText = "VIsUAL"; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, ExpectedAutoCompleteText); + } + + [Test] + public void MainViewModel_GetAutoCompleteTextReturnsEmptyString_WhenIndexIsZeroAndNoMatch() + { + // Arrange + int index = 0; + string input = "VISUAL"; + String query = "Vim"; + string ExpectedAutoCompleteText = string.Empty; + + // Act + string autoCompleteText = MainViewModel.GetAutoCompleteText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, ExpectedAutoCompleteText); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsEmptyString_WhenInputIsNull() + { + // Arrange + int index = 0; + string input = null; + String query = "M"; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsEmptyString_WhenInputIsEmpty() + { + // Arrange + int index = 0; + string input = string.Empty; + String query = "M"; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, string.Empty); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsInputString_WhenQueryIsNull() + { + // Arrange + int index = 0; + string input = "Visual"; + String query = null; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, input); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsInputString_WhenQueryIsEmpty() + { + // Arrange + int index = 0; + string input = "Visual"; + String query = string.Empty; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, input); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsMatchingStringWithCase_WhenIndexIsZeroAndMatch() + { + // Arrange + int index = 0; + string input = "VISUAL"; + String query = "VIs"; + string ExpectedAutoCompleteText = "VIsUAL"; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, ExpectedAutoCompleteText); + } + + [Test] + public void MainViewModel_GetSearchTextReturnsInput_WhenIndexIsZeroAndNoMatch() + { + // Arrange + int index = 0; + string input = "VISUAL"; + String query = "Vim"; + + // Act + string autoCompleteText = MainViewModel.GetSearchText(index, input, query); + + // Assert + Assert.AreEqual(autoCompleteText, input); + } + } +} diff --git a/src/modules/launcher/Wox/ViewModel/MainViewModel.cs b/src/modules/launcher/Wox/ViewModel/MainViewModel.cs index c3669892a5..a90a091290 100644 --- a/src/modules/launcher/Wox/ViewModel/MainViewModel.cs +++ b/src/modules/launcher/Wox/ViewModel/MainViewModel.cs @@ -709,6 +709,40 @@ namespace Wox.ViewModel } } + public static string GetAutoCompleteText(int index, string input, String query) + { + if (!string.IsNullOrEmpty(input) && !string.IsNullOrEmpty(query)) + { + if (index == 0) + { + if (input.IndexOf(query, StringComparison.InvariantCultureIgnoreCase) == 0) + { + // Use the same case as the input query for the matched portion of the string + return query + input.Substring(query.Length); + } + } + } + + return string.Empty; + } + + public static string GetSearchText(int index, String input, string query) + { + if (!string.IsNullOrEmpty(input)) + { + if (index == 0 && !string.IsNullOrEmpty(query)) + { + if (input.IndexOf(query, StringComparison.InvariantCultureIgnoreCase) == 0) + { + return query + input.Substring(query.Length); + } + } + return input; + } + + return string.Empty; + } + protected virtual void Dispose(bool disposing) { if (!_disposed)