diff --git a/CHANGELOG.md b/CHANGELOG.md index c86ffc5..9845f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 (default **10 seconds**; **0** closes immediately), and selecting **Never** turns auto-close off entirely. +### Changed + +- **MRU suggestions no longer drop down on focus.** The Branch and Solution boxes used to open + their recently-used list the moment they were focused — so the window started up looking like it + had a list permanently stuck open. The list now appears only when you start typing or summon it + with **Ctrl+Space** (when there's history to show). The list also keeps the **10** most recent + entries per field (was 12). + ### Fixed - **The chooser dialog is now fully keyboard-driven.** Up/Down arrows move the highlighted diff --git a/src/Models/Mru.cs b/src/Models/Mru.cs index 5f39784..4f39b88 100644 --- a/src/Models/Mru.cs +++ b/src/Models/Mru.cs @@ -9,7 +9,7 @@ namespace Fido.Models; public static class Mru { /// Most entries kept per list. - public const int MaxItems = 12; + public const int MaxItems = 10; /// /// Promotes to the front, removing any earlier (case-insensitive) diff --git a/src/Views/MainWindow.axaml b/src/Views/MainWindow.axaml index 4100123..213c85a 100644 --- a/src/Views/MainWindow.axaml +++ b/src/Views/MainWindow.axaml @@ -4,8 +4,8 @@ xmlns:sys="using:System" x:Class="Fido.Views.MainWindow" x:DataType="vm:MainWindowViewModel" - Width="600" Height="680" - MinWidth="520" MinHeight="520" + Width="600" Height="780" + MinWidth="520" MinHeight="560" WindowStartupLocation="CenterScreen" Icon="/Assets/fido-icon-256.png" Title="Fido" @@ -40,8 +40,7 @@ + FilterMode="Contains" MinimumPrefixLength="0"> @@ -67,7 +66,6 @@ Text="{Binding SolutionName, Mode=TwoWay}" ItemsSource="{Binding RecentSolutions}" FilterMode="Contains" MinimumPrefixLength="0" - GotFocus="OnMruGotFocus" PlaceholderText="blank → find the branch's folder and list its solutions"> @@ -172,7 +170,7 @@ VerticalAlignment="Center" Margin="8,0,0,0" /> + BorderThickness="1" CornerRadius="8" Padding="15,14" MinHeight="190"> diff --git a/src/Views/MainWindow.axaml.cs b/src/Views/MainWindow.axaml.cs index 3fd7c7e..9cf9fe5 100644 --- a/src/Views/MainWindow.axaml.cs +++ b/src/Views/MainWindow.axaml.cs @@ -118,13 +118,6 @@ private void OnEditorShortcutKeyDown(object? sender, KeyEventArgs e) _ => null, }; - // Surface the MRU suggestions as soon as a field is focused — but only when there's history to show. - private void OnMruGotFocus(object? sender, FocusChangedEventArgs e) - { - if (sender is AutoCompleteBox { ItemsSource: ICollection { Count: > 0 } } box) - Dispatcher.UIThread.Post(() => box.IsDropDownOpen = true); - } - /// Promotes the entered branch/solution to the front of the MRU lists and persists them. private void RecordMru(string branch, string solution) { @@ -253,14 +246,30 @@ private sealed record StartupPlan(bool AutoOpen, Editor? Editor, string? Unknown private async void OnOpenClick(object? sender, RoutedEventArgs e) => await RunOpenAsync(); - // Enter inside the branch/solution boxes opens directly. The AutoCompleteBox eats the first - // Enter just to close its MRU drop-down, so without this a pasted branch needs a second Enter - // to act. Close the drop-down, swallow the key so the default button can't also fire, then run - // the open flow — collapsing it back to a single press. Posted so any pending selection/binding - // settles before RunOpenAsync reads the branch name. + // Key handling for the branch/solution boxes. + // + // Ctrl+Space summons the MRU suggestions on demand. The boxes no longer drop the list down on + // focus (it looked permanently stuck open); instead the list appears when the user starts typing + // or asks for it with this gesture — but only when there's history to show. + // + // Enter opens directly. The AutoCompleteBox eats the first Enter just to close its MRU drop-down, + // so without this a pasted branch needs a second Enter to act. Close the drop-down, swallow the + // key so the default button can't also fire, then run the open flow — collapsing it back to a + // single press. Posted so any pending selection/binding settles before RunOpenAsync reads the + // branch name. private void OnInputBoxKeyDown(object? sender, KeyEventArgs e) { - if (e.Key != Key.Enter || sender is not AutoCompleteBox box) return; + if (sender is not AutoCompleteBox box) return; + + if (e.Key == Key.Space && e.KeyModifiers == KeyModifiers.Control) + { + if (box.ItemsSource is not ICollection { Count: > 0 }) return; + e.Handled = true; + box.IsDropDownOpen = true; + return; + } + + if (e.Key != Key.Enter) return; box.IsDropDownOpen = false; e.Handled = true; Dispatcher.UIThread.Post(() => _ = RunOpenAsync(), DispatcherPriority.Input); diff --git a/tests/Fido.Tests/E2E/StartupAndValidationTests.cs b/tests/Fido.Tests/E2E/StartupAndValidationTests.cs index 898fcd1..7eaf5f7 100644 --- a/tests/Fido.Tests/E2E/StartupAndValidationTests.cs +++ b/tests/Fido.Tests/E2E/StartupAndValidationTests.cs @@ -419,10 +419,16 @@ await Harness.WithWindow(services, async window => window.SetText("BranchBox", "main"); window.SetText("SolutionBox", "Foo"); - // Focusing the box surfaces the MRU drop-down (OnMruGotFocus) — the state the user is - // in when they hit Enter. Assert it's actually showing so we exercise the real swallow. + // Ctrl+Space summons the MRU drop-down (the boxes no longer open it on focus) — the + // state the user is in when they hit Enter. Assert it's showing so we exercise the swallow. var box = window.FindControl("BranchBox")!; box.Focus(); + box.RaiseEvent(new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = Key.Space, + KeyModifiers = KeyModifiers.Control, + }); UiTestExtensions.Pump(); await Assert.That(box.IsDropDownOpen).IsTrue();