Public Access
Desktop: rebuild the hosts board once the typing in the find box pauses, not once a letter
This commit is contained in:
1 parent
8759b12d47
commit
24c18205c3
3 files changed
+94
-1
No files matched your search
@@ -230,9 +230,13 @@
|
|||||||
|
|
||||||
Ctrl+K is named on it because the palette is the other way to reach a host by typing, and somebody
|
Ctrl+K is named on it because the palette is the other way to reach a host by typing, and somebody
|
||||||
who has found this box should know about the one that also connects on Enter.
|
who has found this box should know about the one that also connects on Enter.
|
||||||
|
|
||||||
|
One way, and passed back by the code-behind once the typing pauses: every change to the filter
|
||||||
|
rebuilds the board's sections and their cards, and a name typed at speed used to do that once a
|
||||||
|
letter. The view model still filters the moment it is told. See HostsScreen.OnFilterTyped.
|
||||||
-->
|
-->
|
||||||
<Border Grid.Row="1" Margin="26,0,26,16">
|
<Border Grid.Row="1" Margin="26,0,26,16">
|
||||||
<TextBox x:Name="HostFilter" Text="{Binding HostFilter}" Height="40" CornerRadius="10"
|
<TextBox x:Name="HostFilter" Text="{Binding HostFilter, Mode=OneWay}" Height="40" CornerRadius="10"
|
||||||
FontFamily="{StaticResource MonoFont}"
|
FontFamily="{StaticResource MonoFont}"
|
||||||
PlaceholderText="Find a host by name, address or note… · Ctrl+K searches and connects" />
|
PlaceholderText="Find a host by name, address or note… · Ctrl+K searches and connects" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -106,6 +106,48 @@ internal sealed partial class HostsScreen : UserControl
|
|||||||
Board.AddHandler(ContextRequestedEvent, OnContextRequested, RoutingStrategies.Tunnel);
|
Board.AddHandler(ContextRequestedEvent, OnContextRequested, RoutingStrategies.Tunnel);
|
||||||
|
|
||||||
WireTheBand();
|
WireTheBand();
|
||||||
|
|
||||||
|
HostFilter.TextChanged += OnFilterTyped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>How long the find box waits for the typing to pause before the board is rebuilt.</summary>
|
||||||
|
private static readonly TimeSpan FilterPause = TimeSpan.FromMilliseconds(150);
|
||||||
|
|
||||||
|
/// <summary>The wait itself, replaceable so a test can say when a pause is over rather than sleep through one.</summary>
|
||||||
|
internal Func<TimeSpan, Task> Pause { get; set; } = static span => Task.Delay(span);
|
||||||
|
|
||||||
|
/// <summary>How many times the find box has changed, so a wait can tell it is no longer the latest.</summary>
|
||||||
|
private int typed;
|
||||||
|
|
||||||
|
/// <summary>Hands the find box's text to the vault once the typing pauses.</summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Every change to the filter rebuilds the board's sections and every card in them, and a name typed at
|
||||||
|
/// speed used to do that once a letter. Now it is done once, with the whole of what was typed.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// A wait rather than a binding delay, and on the dispatcher's own queue: the box is bound one way, so a
|
||||||
|
/// filter the vault sets itself — cleared, or restored — still lands in the box at once, and the
|
||||||
|
/// change it makes to the box comes back here as the same text, which changes nothing.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
private void OnFilterTyped(object? sender, TextChangedEventArgs e) =>
|
||||||
|
_ = PassTheFilterOnAsync(HostFilter.Text ?? string.Empty, ++typed);
|
||||||
|
|
||||||
|
private async Task PassTheFilterOnAsync(string text, int keystroke)
|
||||||
|
{
|
||||||
|
await Pause(FilterPause).ConfigureAwait(true);
|
||||||
|
|
||||||
|
// A later letter has its own wait, and it is the one that speaks.
|
||||||
|
if (keystroke != typed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Vault is { } vault && !string.Equals(vault.HostFilter, text, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
vault.HostFilter = text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>The band's own wiring, and the two keys that go with a set.</summary>
|
/// <summary>The band's own wiring, and the two keys that go with a set.</summary>
|
||||||
|
|||||||
@@ -520,6 +520,53 @@ public sealed class HostGridTests : IAsyncLifetime
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// Every change to the filter rebuilds the board's sections and every card in them, and a name typed at
|
||||||
|
/// speed used to do that once a letter. The box now tells the vault once the typing pauses — and then
|
||||||
|
/// exactly once, with the whole of what was typed.
|
||||||
|
/// </remarks>
|
||||||
|
[Fact]
|
||||||
|
public async Task TypingIntoTheFindBox_RebuildsTheBoardOnceThePauseComes_NotOnceALetter()
|
||||||
|
{
|
||||||
|
await OnTheBoardAsync((screen, _) =>
|
||||||
|
{
|
||||||
|
// Each letter's wait, ended by hand: the pause is real time in the application, and this says
|
||||||
|
// when it is over instead of sleeping through it.
|
||||||
|
var pauses = new List<TaskCompletionSource>();
|
||||||
|
|
||||||
|
screen.Pause = _ =>
|
||||||
|
{
|
||||||
|
var pause = new TaskCompletionSource();
|
||||||
|
pauses.Add(pause);
|
||||||
|
return pause.Task;
|
||||||
|
};
|
||||||
|
|
||||||
|
var rebuilds = 0;
|
||||||
|
vault.HostSections.CollectionChanged += (_, _) => rebuilds++;
|
||||||
|
|
||||||
|
var box = screen.FindControl<TextBox>("HostFilter").ShouldNotBeNull();
|
||||||
|
|
||||||
|
box.Text = "p";
|
||||||
|
box.Text = "pr";
|
||||||
|
box.Text = "pro";
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
vault.HostFilter.ShouldBeNullOrEmpty("nothing has reached the vault while the typing goes on");
|
||||||
|
rebuilds.ShouldBe(0);
|
||||||
|
|
||||||
|
foreach (var pause in pauses)
|
||||||
|
{
|
||||||
|
pause.SetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
vault.HostFilter.ShouldBe("pro");
|
||||||
|
rebuilds.ShouldBe(1, "only the last letter's wait passes the text on");
|
||||||
|
vault.VisibleHosts.ShouldHaveSingleItem().Label.ShouldBe("prod-db");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Helpers ----
|
// ---- Helpers ----
|
||||||
|
|
||||||
private static void RightClick(Visual card, Visual window)
|
private static void RightClick(Visual card, Visual window)
|
||||||
|
|||||||
Reference in new issue
Block a user