Skip to content

Commit c70b117

Browse files
authored
Changed the tool infrastructure to make the main menu supporting tree nodes. (#104)
* Changed the tool infrastructure to make the main menu supporting tree nodes. * fixed localized text
1 parent 4d77434 commit c70b117

27 files changed

+1316
-284
lines changed

src/dev/impl/DevToys/Api/Tools/IToolProviderFactory.cs

+14-8
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,27 @@ public interface IToolProviderFactory
1818
IToolViewModel GetToolViewModel(IToolProvider provider);
1919

2020
/// <summary>
21-
/// Gets the list of tools available.
21+
/// Gets a flat list of tools that match the given query.
2222
/// </summary>
23-
/// <param name="searchQuery">If not null or empty, the method will return items that match the given search query and order them.</param>
24-
/// <returns>
25-
/// Returns a list of provider along with an array of parts that matched <paramref name="searchQuery"/>.
26-
/// </returns>
27-
IEnumerable<MatchedToolProvider> GetTools(string? searchQuery);
23+
Task<IEnumerable<MatchedToolProvider>> SearchToolsAsync(string searchQuery);
24+
25+
/// <summary>
26+
/// Gets a hierarchical list of available tools. This does not include footer tools.
27+
/// </summary>
28+
Task<IEnumerable<MatchedToolProvider>> GetToolsTreeAsync();
29+
30+
/// <summary>
31+
/// Gets a flat list containing all the tools available.
32+
/// </summary>
33+
IEnumerable<MatchedToolProvider> GetAllTools();
2834

2935
/// <summary>
3036
/// Gets the list of tools available that have the <see cref="IsFooterItemAttribute"/>.
3137
/// </summary>
32-
IEnumerable<MatchedToolProvider> GetFooterTools();
38+
Task<IEnumerable<MatchedToolProvider>> GetFooterToolsAsync();
3339

3440
/// <summary>
35-
/// Called when the app is shutting down. Asks ever tools to cleanup resources.
41+
/// Called when the app is shutting down. Asks every tools to cleanup resources.
3642
/// </summary>
3743
Task CleanupAsync();
3844
}

src/dev/impl/DevToys/Api/Tools/MatchedToolProvider.cs

+69-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
#nullable enable
22

33
using System;
4+
using System.Collections.Generic;
45
using System.ComponentModel;
6+
using System.Threading.Tasks;
7+
using DevToys.Shared.Core.Threading;
8+
using DevToys.Core.Threading;
59
using DevToys.Shared.Core;
10+
using Windows.UI.Xaml.Controls;
11+
using System.Linq;
612

713
namespace DevToys.Api.Tools
814
{
@@ -11,6 +17,7 @@ namespace DevToys.Api.Tools
1117
/// </summary>
1218
public class MatchedToolProvider : INotifyPropertyChanged
1319
{
20+
private readonly List<MatchedToolProvider> _childrenTools = new();
1421
private MatchSpan[] _matchedSpans = Array.Empty<MatchSpan>();
1522

1623
/// <summary>
@@ -39,13 +46,73 @@ public MatchSpan[] MatchedSpans
3946
/// </summary>
4047
public ToolProviderMetadata Metadata { get; }
4148

49+
/// <summary>
50+
/// Gets whether the tool should be highlighted in the UI following a smart detection that the tool could be useful for the user.
51+
/// </summary>
52+
public bool IsRecommended { get; private set; }
53+
54+
public IReadOnlyList<MatchedToolProvider> ChildrenTools
55+
{
56+
get => _childrenTools;
57+
set
58+
{
59+
_childrenTools.Clear();
60+
if (value is not null)
61+
{
62+
foreach (MatchedToolProvider item in value)
63+
{
64+
AddChildTool(item);
65+
}
66+
}
67+
}
68+
}
69+
70+
public bool HasRecommandedChildrenTool => ChildrenTools.Any(item => item.IsRecommended || item.HasRecommandedChildrenTool);
71+
72+
internal TaskCompletionNotifier<IconElement> Icon => (TaskCompletionNotifier<IconElement>)ToolProvider.IconSource;
73+
4274
public event PropertyChangedEventHandler? PropertyChanged;
4375

44-
public MatchedToolProvider(ToolProviderMetadata metadata, IToolProvider toolProvider, MatchSpan[] matchedSpans)
76+
public MatchedToolProvider(ToolProviderMetadata metadata, IToolProvider toolProvider, MatchSpan[]? matchedSpans = null)
4577
{
4678
Metadata = Arguments.NotNull(metadata, nameof(metadata));
4779
ToolProvider = Arguments.NotNull(toolProvider, nameof(toolProvider));
48-
MatchedSpans = Arguments.NotNull(matchedSpans, nameof(matchedSpans));
80+
MatchedSpans = matchedSpans ?? Array.Empty<MatchSpan>();
81+
}
82+
83+
internal async Task UpdateIsRecommendedAsync(string clipboardContent)
84+
{
85+
await TaskScheduler.Default;
86+
87+
IsRecommended = ToolProvider.CanBeTreatedByTool(clipboardContent);
88+
89+
ThreadHelper.RunOnUIThreadAsync(() =>
90+
{
91+
RaisePropertyChanged(nameof(IsRecommended));
92+
}).Forget();
93+
}
94+
95+
internal void AddChildTool(MatchedToolProvider child)
96+
{
97+
Arguments.NotNull(child, nameof(child));
98+
99+
_childrenTools.Add(child);
100+
101+
if (child.IsRecommended)
102+
{
103+
RaisePropertyChanged(nameof(HasRecommandedChildrenTool));
104+
}
105+
106+
child.PropertyChanged += Child_PropertyChanged;
107+
}
108+
109+
private void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)
110+
{
111+
if ((e.PropertyName == nameof(IsRecommended) || e.PropertyName == nameof(HasRecommandedChildrenTool))
112+
&& HasRecommandedChildrenTool)
113+
{
114+
RaisePropertyChanged(nameof(HasRecommandedChildrenTool));
115+
}
49116
}
50117

51118
protected void RaisePropertyChanged(string propertyName)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#nullable enable
2+
3+
using System;
4+
using System.Composition;
5+
6+
namespace DevToys.Api.Tools
7+
{
8+
/// <summary>
9+
/// Indicates the parent tool of the current one.
10+
/// The name should corresponds to an existing <see cref="NameAttribute.Name"/> value, or null if no parent.
11+
/// </summary>
12+
[MetadataAttribute]
13+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
14+
public sealed class ParentAttribute : Attribute
15+
{
16+
public string Parent { get; set; }
17+
18+
public ParentAttribute(string? name)
19+
{
20+
Parent = name ?? string.Empty;
21+
}
22+
}
23+
}

src/dev/impl/DevToys/Api/Tools/ToolProviderMetadata.cs

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ public sealed class ToolProviderMetadata
1212
[DefaultValue("Unnamed")]
1313
public string Name { get; set; } = string.Empty;
1414

15+
/// <summary>
16+
/// Gets or sets the internal non-localized name of the parent provider.
17+
/// </summary>
18+
[DefaultValue("")]
19+
public string Parent { get; set; } = string.Empty;
20+
1521
/// <summary>
1622
/// Gets or sets the order in which this tool should appear.
1723
/// </summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#nullable enable
2+
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
using System.Collections.Specialized;
6+
using DevToys.Shared.Core;
7+
8+
namespace DevToys.Core.Collections
9+
{
10+
public class ExtendedObservableCollection<T> : ObservableCollection<T>
11+
{
12+
/// <summary>
13+
/// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
14+
/// </summary>
15+
internal void AddRange(IEnumerable<T> collection)
16+
{
17+
Arguments.NotNull(collection, nameof(collection));
18+
19+
foreach (T item in collection)
20+
{
21+
Items.Add(item);
22+
}
23+
24+
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
25+
}
26+
}
27+
}

src/dev/impl/DevToys/Core/Collections/OrderedObservableCollection.cs

-50
This file was deleted.

0 commit comments

Comments
 (0)