refactor: tighten tray menu section handling
PR and Push Build/Test / build-and-test (push) Successful in 10m51s

This commit is contained in:
2026-08-04 10:11:43 +02:00
parent 2f12a96688
commit aa42e8edda
3 changed files with 59 additions and 56 deletions
+50 -53
View File
@@ -13,22 +13,23 @@ public sealed class TaskbarIconTests
{ {
var menu = MeetingTaskbarMenuBuilder.Build( var menu = MeetingTaskbarMenuBuilder.Build(
Status(), Status(),
[Profile("default", "Ctrl+Alt+M"), Profile("english", "Ctrl+Alt+L")]); [Profile("default", "Ctrl+Alt+M"), Profile("english", "Ctrl+Alt+L")],
[new MicrophoneDevice("integrated", "integrated microphone")],
"integrated");
Assert.Equal(RecordingProcessState.Idle, menu.State); Assert.Equal(RecordingProcessState.Idle, menu.State);
Assert.Contains(menu.Items, item => AssertMenuLayout(
item.Action == MeetingTaskbarAction.EditRules && menu,
item.Text == "Open agent"); ("Open agent", MeetingTaskbarAction.EditRules, false),
Assert.Contains(menu.Items, item => ("Microphone", MeetingTaskbarAction.OpenSubmenu, true),
item.Action == MeetingTaskbarAction.StartRecording && ("Start meeting recording (default)\tCtrl+Alt+M", MeetingTaskbarAction.StartRecording, false),
item.ProfileName == "default" && ("Start meeting recording (english)\tCtrl+Alt+L", MeetingTaskbarAction.StartRecording, false),
item.Text == "Start meeting recording (default)\tCtrl+Alt+M"); ("Exit", MeetingTaskbarAction.Exit, true));
Assert.Contains(menu.Items, item => Assert.Equal(
item.Action == MeetingTaskbarAction.StartRecording && ["default", "english"],
item.ProfileName == "english" && menu.Items
item.Text == "Start meeting recording (english)\tCtrl+Alt+L"); .Where(item => item.Action == MeetingTaskbarAction.StartRecording)
Assert.DoesNotContain(menu.Items, item => item.Action == MeetingTaskbarAction.StopRecording); .Select(item => item.ProfileName));
Assert.DoesNotContain(menu.Items, item => item.Action == MeetingTaskbarAction.AbortRecording);
} }
[Fact] [Fact]
@@ -69,45 +70,32 @@ public sealed class TaskbarIconTests
"integrated"); "integrated");
Assert.Equal(RecordingProcessState.Recording, menu.State); Assert.Equal(RecordingProcessState.Recording, menu.State);
Assert.Collection( AssertMenuLayout(
menu.Items, menu,
item => ("Open agent", MeetingTaskbarAction.EditRules, false),
{ ("Finish meeting", MeetingTaskbarAction.StopRecording, true),
Assert.Equal("Open agent", item.Text); ("Microphone", MeetingTaskbarAction.OpenSubmenu, true),
Assert.Equal(MeetingTaskbarAction.EditRules, item.Action); ("Cancel meeting recording and discard", MeetingTaskbarAction.AbortRecording, false),
Assert.False(item.StartsSection); ("Switch to english\tCtrl+Alt+L", MeetingTaskbarAction.SwitchProfile, false),
}, ("Exit", MeetingTaskbarAction.Exit, true));
item => Assert.Equal(
{ "english",
Assert.Equal("Finish meeting", item.Text); Assert.Single(menu.Items, item => item.Action == MeetingTaskbarAction.SwitchProfile).ProfileName);
Assert.Equal(MeetingTaskbarAction.StopRecording, item.Action); }
Assert.True(item.StartsSection);
}, [Fact]
item => public void RecordingMenuKeepsFinishMeetingIsolatedWithoutMicrophones()
{ {
Assert.Equal("Microphone", item.Text); var menu = MeetingTaskbarMenuBuilder.Build(
Assert.Equal(MeetingTaskbarAction.OpenSubmenu, item.Action); Status(isRecording: true, state: RecordingProcessState.Recording, profile: "default"),
Assert.True(item.StartsSection); [Profile("default")]);
},
item => AssertMenuLayout(
{ menu,
Assert.Equal("Cancel meeting recording and discard", item.Text); ("Open agent", MeetingTaskbarAction.EditRules, false),
Assert.Equal(MeetingTaskbarAction.AbortRecording, item.Action); ("Finish meeting", MeetingTaskbarAction.StopRecording, true),
Assert.False(item.StartsSection); ("Cancel meeting recording and discard", MeetingTaskbarAction.AbortRecording, true),
}, ("Exit", MeetingTaskbarAction.Exit, true));
item =>
{
Assert.Equal("Switch to english\tCtrl+Alt+L", item.Text);
Assert.Equal(MeetingTaskbarAction.SwitchProfile, item.Action);
Assert.Equal("english", item.ProfileName);
Assert.False(item.StartsSection);
},
item =>
{
Assert.Equal("Exit", item.Text);
Assert.Equal(MeetingTaskbarAction.Exit, item.Action);
Assert.True(item.StartsSection);
});
} }
[Fact] [Fact]
@@ -200,6 +188,15 @@ public sealed class TaskbarIconTests
}); });
} }
private static void AssertMenuLayout(
MeetingTaskbarMenu menu,
params (string Text, MeetingTaskbarAction Action, bool StartsSection)[] expected)
{
Assert.Equal(
expected,
menu.Items.Select(item => (item.Text, item.Action, item.StartsSection)));
}
private static RecordingStatus Status( private static RecordingStatus Status(
bool isRecording = false, bool isRecording = false,
RecordingProcessState state = RecordingProcessState.Idle, RecordingProcessState state = RecordingProcessState.Idle,
@@ -113,15 +113,15 @@ public static class MeetingTaskbarMenuBuilder
private static void AddSection( private static void AddSection(
List<MeetingTaskbarMenuItem> items, List<MeetingTaskbarMenuItem> items,
List<MeetingTaskbarMenuItem> section) IReadOnlyList<MeetingTaskbarMenuItem> section)
{ {
if (section.Count == 0) if (section.Count == 0)
{ {
return; return;
} }
section[0] = section[0] with { StartsSection = true }; items.Add(section[0] with { StartsSection = true });
items.AddRange(section); items.AddRange(section.Skip(1));
} }
private static string BuildTooltip(RecordingStatus status) private static string BuildTooltip(RecordingStatus status)
@@ -7,3 +7,9 @@
- [x] 2.1 Review the touched menu builder and renderer for DRYness, SOLID design, and simplicity while preserving behavior. - [x] 2.1 Review the touched menu builder and renderer for DRYness, SOLID design, and simplicity while preserving behavior.
- [x] 2.2 Run focused taskbar-menu tests, the Windows application build, the full solution tests, and strict OpenSpec validation. - [x] 2.2 Run focused taskbar-menu tests, the Windows application build, the full solution tests, and strict OpenSpec validation.
## 3. Refactor Follow-up
- [x] 3.1 Lock down idle section boundaries and active-recording layout when no microphone is available.
- [x] 3.2 Remove the tray-menu section helper's hidden input mutation without changing rendered behavior.
- [x] 3.3 Run focused and full verification, then validate the OpenSpec change strictly.