Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved search results to AutoSuggestedBox instead of NavigationView #105

Merged
merged 1 commit into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/dev/impl/DevToys/Api/Tools/MatchedToolProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ public MatchSpan[] MatchedSpans
set
{
_matchedSpans = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AnyMatchedSpan)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MatchedSpans)));
ThreadHelper.RunOnUIThreadAsync(() =>
{
RaisePropertyChanged(nameof(AnyMatchedSpan));
RaisePropertyChanged(nameof(MatchedSpans));
}).Forget();
}
}

Expand Down Expand Up @@ -73,11 +76,11 @@ public IReadOnlyList<MatchedToolProvider> ChildrenTools

public event PropertyChangedEventHandler? PropertyChanged;

public MatchedToolProvider(ToolProviderMetadata metadata, IToolProvider toolProvider, MatchSpan[]? matchedSpans = null)
public MatchedToolProvider(ToolProviderMetadata metadata, IToolProvider toolProvider)
{
Metadata = Arguments.NotNull(metadata, nameof(metadata));
ToolProvider = Arguments.NotNull(toolProvider, nameof(toolProvider));
MatchedSpans = matchedSpans ?? Array.Empty<MatchSpan>();
MatchedSpans = Array.Empty<MatchSpan>();
}

internal async Task UpdateIsRecommendedAsync(string clipboardContent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using DevToys.Shared.Core;

namespace DevToys.Core.Collections
Expand All @@ -23,5 +24,44 @@ internal void AddRange(IEnumerable<T> collection)

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

/// <summary>
/// Update the difference between the current items in the collection and the <paramref name="newItems"/>.
/// </summary>
internal void Update(IEnumerable<T> newItems)
{
// First, remove the items that aren't part of the new list items.
var oldToolsMenuItems = this.ToList();
for (int i = 0; i < oldToolsMenuItems.Count; i++)
{
T item = oldToolsMenuItems[i];
if (!newItems.Contains(item))
{
Remove(item);
}
}

// Then:
// 1. If an item from newItems already exist in the collection, but at a different position, move it to the desired index.
// 2. If an item from newItems doesn't exist in the collection, insert it with respect of the position of older items in the collection.
int insertionIndex = 0;
foreach (T? item in newItems)
{
int indexOfItemInOldMenu = IndexOf(item);
if (indexOfItemInOldMenu > -1)
{
if (indexOfItemInOldMenu != insertionIndex)
{
Move(indexOfItemInOldMenu, insertionIndex);
}
}
else
{
Insert(insertionIndex, item);
}

insertionIndex++;
}
}
}
}
47 changes: 22 additions & 25 deletions src/dev/impl/DevToys/Core/ToolProviderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ public async Task<IEnumerable<MatchedToolProvider>> SearchToolsAsync(string sear

return
SortTools(
SearchTools(
GetAllTools(),
searchQueries)
SearchTools(searchQueries)
.ToList());
}

Expand Down Expand Up @@ -104,38 +102,37 @@ private async void OnAppSuspending(object sender, Windows.ApplicationModel.Suspe
await CleanupAsync();
}

private IEnumerable<MatchedToolProvider> SearchTools(IEnumerable<MatchedToolProvider> providers, string[]? searchQueries)
private IEnumerable<MatchedToolProvider> SearchTools(string[]? searchQueries)
{
if (searchQueries is not null)
{
foreach (MatchedToolProvider provider in providers)
foreach (MatchedToolProvider provider in GetAllTools())
{
var matches = new List<MatchSpan>();

foreach (string? query in searchQueries)
if (provider.ChildrenTools.Count == 0) // do not search groups.
{
int i = 0;
while (i < provider.ToolProvider.DisplayName?.Length && i > -1)
var matches = new List<MatchSpan>();

foreach (string? query in searchQueries)
{
int matchIndex = provider.ToolProvider.DisplayName.IndexOf(query, i, StringComparison.OrdinalIgnoreCase);
if (matchIndex > -1)
int i = 0;
while (i < provider.ToolProvider.DisplayName?.Length && i > -1)
{
matches.Add(new MatchSpan(matchIndex, query.Length));
i = matchIndex + query.Length;
int matchIndex = provider.ToolProvider.DisplayName.IndexOf(query, i, StringComparison.OrdinalIgnoreCase);
if (matchIndex > -1)
{
matches.Add(new MatchSpan(matchIndex, query.Length));
i = matchIndex + query.Length;
}

i++;
}

i++;
}
}

if (matches.Count > 0)
{
// Return a new MatchedToolProvider with the matches.
yield return
new MatchedToolProvider(
provider.Metadata,
provider.ToolProvider,
matches.ToArray());
if (matches.Count > 0)
{
provider.MatchedSpans = matches.ToArray();
yield return provider;
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/dev/impl/DevToys/DevToys.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<Compile Include="Core\OOP\AppService.cs" />
<Compile Include="Core\Threading\AsyncLazy.cs" />
<Compile Include="Helpers\NumberBaseHelper.cs" />
<Compile Include="Models\NoResultFoundMockToolProvider.cs" />
<Compile Include="Models\Radix.cs" />
<Compile Include="Models\NumberBaseFormat.cs" />
<Compile Include="UI\Converters\BooleanToDoubleConverter.cs" />
Expand Down
5 changes: 5 additions & 0 deletions src/dev/impl/DevToys/LanguageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,11 @@ public string GetFormattedNotificationReleaseNoteTitle(string? param0)
/// </summary>
public string Search => _resources.GetString("Search");

/// <summary>
/// Gets the resource SearchNoResultsFound.
/// </summary>
public string SearchNoResultsFound => _resources.GetString("SearchNoResultsFound");

/// <summary>
/// Gets the resource WindowTitle.
/// </summary>
Expand Down
30 changes: 30 additions & 0 deletions src/dev/impl/DevToys/Models/NoResultFoundMockToolProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#nullable enable

using System;
using System.ComponentModel;
using DevToys.Api.Tools;

namespace DevToys.Models
{
internal sealed class NoResultFoundMockToolProvider : IToolProvider
{
public string DisplayName => LanguageManager.Instance.MainPage.SearchNoResultsFound;

public string AccessibleName => LanguageManager.Instance.MainPage.SearchNoResultsFound;

public object IconSource => null!;

public event PropertyChangedEventHandler? PropertyChanged;

public bool CanBeTreatedByTool(string data)
{
return false;
}

public IToolViewModel CreateTool()
{
// TODO: Show a page indicating "No results match your search".
throw new NotSupportedException();
}
}
}
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/cs-CZ/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>Hledat nástroje...</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>No results found</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/en-US/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>Type to search for tools...</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>No results found</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/fr-FR/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>Taper pour recherche un outil...</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>Aucun résultat trouvé</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/pl-PL/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>Wpisz, aby wyszukać narzędzia...</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>No results found</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/ru-RU/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>Найти инструмент</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>No results found</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/dev/impl/DevToys/Strings/zh-CN/MainPage.resw
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="Search" xml:space="preserve">
<value>搜索工具…</value>
</data>
<data name="SearchNoResultsFound" xml:space="preserve">
<value>No results found</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>DevToys</value>
</data>
Expand Down
86 changes: 84 additions & 2 deletions src/dev/impl/DevToys/ViewModels/MainPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using DevToys.Core.Settings;
using DevToys.Core.Threading;
using DevToys.Messages;
using DevToys.Models;
using DevToys.Shared.Core;
using DevToys.Shared.Core.Threading;
using Microsoft.Toolkit.Mvvm.ComponentModel;
Expand Down Expand Up @@ -120,6 +121,11 @@ internal string? SearchQuery
}
}

/// <summary>
/// Gets or sets the list of items to displayed in the Search Box after a search.
/// </summary>
internal ExtendedObservableCollection<MatchedToolProvider> SearchResults { get; } = new();

/// <summary>
/// Gets whether the window is in Compact Overlay mode or not.
/// </summary>
Expand Down Expand Up @@ -184,6 +190,8 @@ public MainPageViewModel(

OpenToolInNewWindowCommand = new AsyncRelayCommand<ToolProviderMetadata>(ExecuteOpenToolInNewWindowCommandAsync);
ChangeViewModeCommand = new AsyncRelayCommand<ApplicationViewMode>(ExecuteChangeViewModeCommandAsync);
SearchBoxTextChangedCommand = new AsyncRelayCommand<Windows.UI.Xaml.Controls.AutoSuggestBoxTextChangedEventArgs>(ExecuteSearchBoxTextChangedCommandAsync);
SearchBoxQuerySubmittedCommand = new RelayCommand<Windows.UI.Xaml.Controls.AutoSuggestBoxQuerySubmittedEventArgs>(ExecuteSearchBoxQuerySubmittedCommand);

_menuInitializationTask = BuildMenuAsync();

Expand Down Expand Up @@ -227,6 +235,80 @@ await ThreadHelper.RunOnUIThreadAsync(() =>

#endregion

#region SearchBoxTextChangedCommand

public IAsyncRelayCommand<Windows.UI.Xaml.Controls.AutoSuggestBoxTextChangedEventArgs> SearchBoxTextChangedCommand { get; }

private async Task ExecuteSearchBoxTextChangedCommandAsync(Windows.UI.Xaml.Controls.AutoSuggestBoxTextChangedEventArgs? parameters)
{
Arguments.NotNull(parameters, nameof(parameters));

await TaskScheduler.Default;

MatchedToolProvider[]? searchResult = null;

if (parameters!.Reason == Windows.UI.Xaml.Controls.AutoSuggestionBoxTextChangeReason.UserInput)
{
string? searchQuery = SearchQuery;
if (!string.IsNullOrEmpty(searchQuery))
{
IEnumerable<MatchedToolProvider> matchedTools
= await _toolProviderFactory.SearchToolsAsync(searchQuery!).ConfigureAwait(false);

if (matchedTools.Any())
{
searchResult = matchedTools.ToArray();
}
else
{
searchResult = new[]
{
new MatchedToolProvider(new ToolProviderMetadata(), new NoResultFoundMockToolProvider())
};
}
}
}

await ThreadHelper.RunOnUIThreadAsync(() =>
{
if (searchResult is null)
{
SearchResults.Clear();
}
else
{
SearchResults.Update(searchResult);
}
});
}

#endregion

#region SearchBoxQuerySubmittedCommand

public IRelayCommand<Windows.UI.Xaml.Controls.AutoSuggestBoxQuerySubmittedEventArgs> SearchBoxQuerySubmittedCommand { get; }

private void ExecuteSearchBoxQuerySubmittedCommand(Windows.UI.Xaml.Controls.AutoSuggestBoxQuerySubmittedEventArgs? parameters)
{
Arguments.NotNull(parameters, nameof(parameters));

if (string.IsNullOrEmpty(parameters!.QueryText))
{
// Nothing has been search. Do nothing.
return;
}

if (parameters.ChosenSuggestion is null or NoResultFoundMockToolProvider)
{
// TODO: Show a page indicating "No results match your search".
return;
}

SetSelectedMenuItem((MatchedToolProvider)parameters.ChosenSuggestion!, clipboardContentData: null);
}

#endregion

/// <summary>
/// Invoked when the Page is loaded and becomes the current source of a parent Frame.
/// </summary>
Expand Down Expand Up @@ -309,8 +391,8 @@ private async Task BuildMenuAsync()

try
{
IEnumerable<MatchedToolProvider> tools = await _toolProviderFactory.GetToolsTreeAsync();
IEnumerable<MatchedToolProvider> footerTools = await _toolProviderFactory.GetFooterToolsAsync();
IEnumerable<MatchedToolProvider> tools = await _toolProviderFactory.GetToolsTreeAsync().ConfigureAwait(false);
IEnumerable<MatchedToolProvider> footerTools = await _toolProviderFactory.GetFooterToolsAsync().ConfigureAwait(false);

await ThreadHelper.RunOnUIThreadAsync(
ThreadPriority.Low,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace DevToys.ViewModels.Tools
[Export(typeof(IToolProvider))]
[Name(InternalName)]
[Parent(TextGroupToolProvider.InternalName)]
[ProtocolName("text")]
[ProtocolName("formatters")]
[Order(2)]
internal sealed class FormattersGroupToolProvider : ToolProviderBase, IToolProvider
{
Expand Down
Loading