feat: recording capsule visible in fullscreen and clicking doesnt focus main window (#46)

This commit is contained in:
Owen Gretzinger
2025-07-25 17:31:20 -04:00
committed by GitHub
parent c8f52cdb1f
commit 2136563428
2 changed files with 53 additions and 54 deletions
-27
View File
@@ -44,19 +44,7 @@ struct MeetingnotesApp: App {
CommandGroup(after: .appInfo) {
CheckForUpdatesView(updater: updaterController.updater)
}
// Hidden command group that handles audio level window notifications
CommandGroup(after: .windowArrangement) {
ShowAudioLevelsCommand()
}
}
// Floating Audio Level Window
Window("", id: "audio-levels") {
AudioLevelWindowView()
}
.windowStyle(.plain)
.windowResizability(.contentSize)
.defaultPosition(.trailing)
}
}
@@ -70,18 +58,3 @@ struct CheckForUpdatesView: View {
.keyboardShortcut("u", modifiers: .command)
}
}
struct ShowAudioLevelsCommand: View {
@Environment(\.openWindow) private var openWindow
var body: some View {
// Empty view - we only need this for the notification observer
EmptyView()
.onReceive(NotificationCenter.default.publisher(for: .openAudioLevelWindow)) { _ in
openWindow(id: "audio-levels")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
AudioLevelWindowManager.shared.showWindow()
}
}
}
}
+53 -27
View File
@@ -76,7 +76,7 @@ struct AudioLevelWindowView: View {
@StateObject private var audioLevelManager = AudioLevelManager.shared
var body: some View {
let micLevel = audioLevelManager.isRecording ? audioLevelManager.micAudioLevel * 40 : 0
let micLevel = audioLevelManager.isRecording ? audioLevelManager.micAudioLevel * 30 : 0
let systemLevel = audioLevelManager.isRecording ? audioLevelManager.systemAudioLevel * 5 : 0
return DancingAudioBars(
micLevel: micLevel,
@@ -124,42 +124,68 @@ class AudioLevelManager: ObservableObject {
}
}
// MARK: - Audio Level Window Manager
// MARK: - Audio Level Window Manager using NSPanel
@MainActor
class AudioLevelWindowManager: ObservableObject {
static let shared = AudioLevelWindowManager()
private init() {}
private var audioLevelPanel: NSPanel?
private init() {
setupPanel()
}
private func setupPanel() {
let panelRect = NSRect(x: 0, y: 0, width: 60, height: 80)
audioLevelPanel = NSPanel(
contentRect: panelRect,
styleMask: [.nonactivatingPanel, .borderless],
backing: .buffered,
defer: true
)
guard let panel = audioLevelPanel else { return }
// Configure panel properties inspired by the provided code
panel.level = .mainMenu
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
panel.isFloatingPanel = true
panel.isMovableByWindowBackground = true
panel.hasShadow = true
panel.backgroundColor = .clear
panel.isOpaque = false
panel.identifier = NSUserInterfaceItemIdentifier("audio-levels")
// Set up the SwiftUI hosting view
let hostingView = NSHostingView(rootView: AudioLevelWindowView())
hostingView.frame = panelRect
panel.contentView = hostingView
// Position the panel in the top-right corner of the screen
if let screen = NSScreen.main {
let screenFrame = screen.visibleFrame
let panelFrame = NSRect(
x: screenFrame.maxX - panelRect.width - 20,
y: screenFrame.maxY - panelRect.height - 20,
width: panelRect.width,
height: panelRect.height
)
panel.setFrame(panelFrame, display: false)
}
}
func showWindow() {
// Find the audio levels window and bring it to front
for window in NSApplication.shared.windows {
if window.identifier?.rawValue == "audio-levels" {
window.orderFront(nil)
window.level = .floating
window.collectionBehavior = [.canJoinAllSpaces, .stationary, .ignoresCycle]
window.isMovableByWindowBackground = true
window.hasShadow = true
window.styleMask = [.borderless]
return
}
guard let panel = audioLevelPanel else {
setupPanel()
showWindow()
return
}
// If window not found, post a notification to trigger opening
NotificationCenter.default.post(name: .openAudioLevelWindow, object: nil)
panel.orderFrontRegardless()
}
func hideWindow() {
// Find the audio levels window and hide it
for window in NSApplication.shared.windows {
if window.identifier?.rawValue == "audio-levels" {
window.orderOut(nil)
return
}
}
audioLevelPanel?.orderOut(nil)
}
}
extension Notification.Name {
static let openAudioLevelWindow = Notification.Name("openAudioLevelWindow")
}