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(
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.Contains(menu.Items, item =>
item.Action == MeetingTaskbarAction.EditRules &&
item.Text == "Open agent");
Assert.Contains(menu.Items, item =>
item.Action == MeetingTaskbarAction.StartRecording &&
item.ProfileName == "default" &&
item.Text == "Start meeting recording (default)\tCtrl+Alt+M");
Assert.Contains(menu.Items, item =>
item.Action == MeetingTaskbarAction.StartRecording &&
item.ProfileName == "english" &&
item.Text == "Start meeting recording (english)\tCtrl+Alt+L");
Assert.DoesNotContain(menu.Items, item => item.Action == MeetingTaskbarAction.StopRecording);
Assert.DoesNotContain(menu.Items, item => item.Action == MeetingTaskbarAction.AbortRecording);
AssertMenuLayout(
menu,
("Open agent", MeetingTaskbarAction.EditRules, false),
("Microphone", MeetingTaskbarAction.OpenSubmenu, true),
("Start meeting recording (default)\tCtrl+Alt+M", MeetingTaskbarAction.StartRecording, false),
("Start meeting recording (english)\tCtrl+Alt+L", MeetingTaskbarAction.StartRecording, false),
("Exit", MeetingTaskbarAction.Exit, true));
Assert.Equal(
["default", "english"],
menu.Items
.Where(item => item.Action == MeetingTaskbarAction.StartRecording)
.Select(item => item.ProfileName));
}
[Fact]
@@ -69,45 +70,32 @@ public sealed class TaskbarIconTests
"integrated");
Assert.Equal(RecordingProcessState.Recording, menu.State);
Assert.Collection(
menu.Items,
item =>
{
Assert.Equal("Open agent", item.Text);
Assert.Equal(MeetingTaskbarAction.EditRules, item.Action);
Assert.False(item.StartsSection);
},
item =>
{
Assert.Equal("Finish meeting", item.Text);
Assert.Equal(MeetingTaskbarAction.StopRecording, item.Action);
Assert.True(item.StartsSection);
},
item =>
{
Assert.Equal("Microphone", item.Text);
Assert.Equal(MeetingTaskbarAction.OpenSubmenu, item.Action);
Assert.True(item.StartsSection);
},
item =>
{
Assert.Equal("Cancel meeting recording and discard", item.Text);
Assert.Equal(MeetingTaskbarAction.AbortRecording, item.Action);
Assert.False(item.StartsSection);
},
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);
});
AssertMenuLayout(
menu,
("Open agent", MeetingTaskbarAction.EditRules, false),
("Finish meeting", MeetingTaskbarAction.StopRecording, true),
("Microphone", MeetingTaskbarAction.OpenSubmenu, true),
("Cancel meeting recording and discard", MeetingTaskbarAction.AbortRecording, false),
("Switch to english\tCtrl+Alt+L", MeetingTaskbarAction.SwitchProfile, false),
("Exit", MeetingTaskbarAction.Exit, true));
Assert.Equal(
"english",
Assert.Single(menu.Items, item => item.Action == MeetingTaskbarAction.SwitchProfile).ProfileName);
}
[Fact]
public void RecordingMenuKeepsFinishMeetingIsolatedWithoutMicrophones()
{
var menu = MeetingTaskbarMenuBuilder.Build(
Status(isRecording: true, state: RecordingProcessState.Recording, profile: "default"),
[Profile("default")]);
AssertMenuLayout(
menu,
("Open agent", MeetingTaskbarAction.EditRules, false),
("Finish meeting", MeetingTaskbarAction.StopRecording, true),
("Cancel meeting recording and discard", MeetingTaskbarAction.AbortRecording, true),
("Exit", MeetingTaskbarAction.Exit, true));
}
[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(
bool isRecording = false,
RecordingProcessState state = RecordingProcessState.Idle,
@@ -113,15 +113,15 @@ public static class MeetingTaskbarMenuBuilder
private static void AddSection(
List<MeetingTaskbarMenuItem> items,
List<MeetingTaskbarMenuItem> section)
IReadOnlyList<MeetingTaskbarMenuItem> section)
{
if (section.Count == 0)
{
return;
}
section[0] = section[0] with { StartsSection = true };
items.AddRange(section);
items.Add(section[0] with { StartsSection = true });
items.AddRange(section.Skip(1));
}
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.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.