Add resilient Azure offline transcription backlog
PR and Push Build/Test / build-and-test (push) Successful in 18m41s

This commit is contained in:
2026-06-15 17:26:34 +02:00
parent b22754ce5d
commit b774ccc375
35 changed files with 2456 additions and 198 deletions
+14 -1
View File
@@ -9,7 +9,8 @@ public enum MeetingTaskbarAction
StartRecording,
StopRecording,
AbortRecording,
SwitchProfile
SwitchProfile,
Exit
}
public sealed record MeetingTaskbarMenu(
@@ -61,6 +62,10 @@ public static class MeetingTaskbarMenuBuilder
}
}
items.Add(new MeetingTaskbarMenuItem(
"Exit",
MeetingTaskbarAction.Exit));
return new MeetingTaskbarMenu(
status.State,
BuildTooltip(status),
@@ -96,3 +101,11 @@ public static class MeetingTaskbarMenuBuilder
: $"{text}\t{hotkey.Trim()}";
}
}
public static class MeetingTaskbarExitPolicy
{
public static bool RequiresConfirmation(RecordingStatus status)
{
return status.State != RecordingProcessState.Idle;
}
}
@@ -1,5 +1,6 @@
#if WINDOWS
using System.Drawing;
using System.Windows;
using H.NotifyIcon.Core;
using MeetingAssistant.LaunchProfiles;
using MeetingAssistant.Recording;
@@ -14,6 +15,7 @@ public sealed class UnoTaskbarIconService : IHostedService, IDisposable
private readonly MeetingRecordingCoordinator coordinator;
private readonly ILaunchProfileOptionsProvider launchProfiles;
private readonly IWorkflowRulesEditorWindowService rulesEditorWindow;
private readonly IHostApplicationLifetime applicationLifetime;
private readonly ILogger<UnoTaskbarIconService> logger;
private readonly object sync = new();
private CancellationTokenSource? refreshCancellation;
@@ -28,11 +30,13 @@ public sealed class UnoTaskbarIconService : IHostedService, IDisposable
MeetingRecordingCoordinator coordinator,
ILaunchProfileOptionsProvider launchProfiles,
IWorkflowRulesEditorWindowService rulesEditorWindow,
IHostApplicationLifetime applicationLifetime,
ILogger<UnoTaskbarIconService> logger)
{
this.coordinator = coordinator;
this.launchProfiles = launchProfiles;
this.rulesEditorWindow = rulesEditorWindow;
this.applicationLifetime = applicationLifetime;
this.logger = logger;
}
@@ -182,7 +186,9 @@ public sealed class UnoTaskbarIconService : IHostedService, IDisposable
var popupMenu = new PopupMenu();
for (var index = 0; index < menu.Items.Count; index++)
{
if (index == 1)
if (index == 1 ||
(menu.Items[index].Action == MeetingTaskbarAction.Exit &&
menu.Items[index - 1].Action != MeetingTaskbarAction.EditRules))
{
popupMenu.Items.Add(new PopupMenuSeparator());
}
@@ -222,6 +228,9 @@ public sealed class UnoTaskbarIconService : IHostedService, IDisposable
case MeetingTaskbarAction.SwitchProfile:
await coordinator.ToggleAsync(item.ProfileName, CancellationToken.None);
break;
case MeetingTaskbarAction.Exit:
ExitApplication();
break;
}
RefreshVisualState();
@@ -247,5 +256,32 @@ public sealed class UnoTaskbarIconService : IHostedService, IDisposable
menu.Items.Select(item => $"{item.Action}:{item.ProfileName}:{item.Text}"));
}
private void ExitApplication()
{
var status = coordinator.CurrentStatus;
if (MeetingTaskbarExitPolicy.RequiresConfirmation(status) && !ConfirmExitDuringProcessing(status.State))
{
logger.LogInformation("Taskbar exit canceled while meeting state was {State}", status.State);
return;
}
logger.LogInformation("Taskbar exit requested while meeting state was {State}", status.State);
applicationLifetime.StopApplication();
}
private static bool ConfirmExitDuringProcessing(RecordingProcessState state)
{
var activity = state == RecordingProcessState.Recording
? "A meeting is still recording and transcribing."
: "A stopped meeting is still transcribing, recognizing speakers, or summarizing.";
var result = MessageBox.Show(
$"{activity}\n\nExit Meeting Assistant anyway?",
"Exit Meeting Assistant",
MessageBoxButton.YesNo,
MessageBoxImage.Warning,
MessageBoxResult.No);
return result == MessageBoxResult.Yes;
}
}
#endif