Files
meeting-assistant/MeetingAssistant/Taskbar/MeetingTaskbarMenu.cs
T
codex 2f12a96688
PR and Push Build/Test / build-and-test (push) Successful in 11m8s
feat: prioritize finish meeting tray action
2026-08-04 09:55:18 +02:00

164 lines
4.9 KiB
C#

using MeetingAssistant.LaunchProfiles;
using MeetingAssistant.Recording;
namespace MeetingAssistant.Taskbar;
public enum MeetingTaskbarAction
{
EditRules,
OpenSubmenu,
StartRecording,
StopRecording,
AbortRecording,
SwitchProfile,
SelectMicrophone,
Exit
}
public sealed record MeetingTaskbarMenu(
RecordingProcessState State,
string Tooltip,
IReadOnlyList<MeetingTaskbarMenuItem> Items);
public sealed record MeetingTaskbarMenuItem(
string Text,
MeetingTaskbarAction Action,
string? ProfileName = null,
string? MicrophoneDeviceId = null,
bool IsChecked = false,
IReadOnlyList<MeetingTaskbarMenuItem>? Items = null,
bool StartsSection = false);
public static class MeetingTaskbarMenuBuilder
{
public static MeetingTaskbarMenu Build(
RecordingStatus status,
IReadOnlyList<LaunchProfile> launchProfiles,
IReadOnlyList<MicrophoneDevice>? microphones = null,
string? currentMicrophoneDeviceId = null)
{
var items = new List<MeetingTaskbarMenuItem>
{
new("Open agent", MeetingTaskbarAction.EditRules)
};
if (status.IsRecording)
{
items.Add(new MeetingTaskbarMenuItem(
"Finish meeting",
MeetingTaskbarAction.StopRecording,
StartsSection: true));
}
var secondaryControls = new List<MeetingTaskbarMenuItem>();
if (microphones is { Count: > 0 })
{
secondaryControls.Add(BuildMicrophoneMenu(microphones, currentMicrophoneDeviceId));
}
if (status.IsRecording)
{
secondaryControls.Add(new MeetingTaskbarMenuItem(
"Cancel meeting recording and discard",
MeetingTaskbarAction.AbortRecording));
foreach (var profile in launchProfiles.Where(profile => !IsActiveProfile(profile, status)))
{
secondaryControls.Add(new MeetingTaskbarMenuItem(
AppendHotkey($"Switch to {profile.Name}", profile.Options.Hotkey.Toggle),
MeetingTaskbarAction.SwitchProfile,
profile.Name));
}
}
else
{
foreach (var profile in launchProfiles)
{
secondaryControls.Add(new MeetingTaskbarMenuItem(
AppendHotkey($"Start meeting recording ({profile.Name})", profile.Options.Hotkey.Toggle),
MeetingTaskbarAction.StartRecording,
profile.Name));
}
}
AddSection(items, secondaryControls);
items.Add(new MeetingTaskbarMenuItem(
"Exit",
MeetingTaskbarAction.Exit,
StartsSection: true));
return new MeetingTaskbarMenu(
status.State,
BuildTooltip(status),
items);
}
private static MeetingTaskbarMenuItem BuildMicrophoneMenu(
IReadOnlyList<MicrophoneDevice> microphones,
string? currentMicrophoneDeviceId)
{
var microphoneItems = microphones
.Select(microphone => new MeetingTaskbarMenuItem(
microphone.Name,
MeetingTaskbarAction.SelectMicrophone,
MicrophoneDeviceId: microphone.Id,
IsChecked: string.Equals(microphone.Id, currentMicrophoneDeviceId, StringComparison.Ordinal)))
.ToArray();
return new MeetingTaskbarMenuItem(
"Microphone",
MeetingTaskbarAction.OpenSubmenu,
Items: microphoneItems);
}
private static void AddSection(
List<MeetingTaskbarMenuItem> items,
List<MeetingTaskbarMenuItem> section)
{
if (section.Count == 0)
{
return;
}
section[0] = section[0] with { StartsSection = true };
items.AddRange(section);
}
private static string BuildTooltip(RecordingStatus status)
{
return status.State switch
{
RecordingProcessState.Recording => string.IsNullOrWhiteSpace(status.LaunchProfile)
? "Meeting Assistant - recording"
: $"Meeting Assistant - recording ({status.LaunchProfile})",
RecordingProcessState.Summarizing => "Meeting Assistant - summarizing",
_ => "Meeting Assistant - idle"
};
}
private static bool IsActiveProfile(
LaunchProfile profile,
RecordingStatus status)
{
return string.Equals(
profile.Name,
status.LaunchProfile,
StringComparison.OrdinalIgnoreCase);
}
private static string AppendHotkey(string text, string hotkey)
{
return string.IsNullOrWhiteSpace(hotkey)
? text
: $"{text}\t{hotkey.Trim()}";
}
}
public static class MeetingTaskbarExitPolicy
{
public static bool RequiresConfirmation(RecordingProcessState state)
{
return state != RecordingProcessState.Idle;
}
}