103 lines
4.0 KiB
Swift
103 lines
4.0 KiB
Swift
import SwiftUI
|
|
|
|
struct MiniRecorderView: View {
|
|
@ObservedObject var whisperState: WhisperState
|
|
@ObservedObject var recorder: Recorder
|
|
@EnvironmentObject var windowManager: MiniWindowManager
|
|
@EnvironmentObject private var enhancementService: AIEnhancementService
|
|
|
|
@State private var showPowerModePopover = false
|
|
@State private var showEnhancementPromptPopover = false
|
|
@State private var isHovering = false
|
|
|
|
// Computed property to check if any popover is currently showing
|
|
private var isAnyPopoverShowing: Bool {
|
|
showPowerModePopover || showEnhancementPromptPopover
|
|
}
|
|
|
|
private var backgroundView: some View {
|
|
ZStack {
|
|
Color.black.opacity(0.9)
|
|
LinearGradient(
|
|
colors: [
|
|
Color.black.opacity(0.95),
|
|
Color(red: 0.15, green: 0.15, blue: 0.15).opacity(0.9)
|
|
],
|
|
startPoint: .top,
|
|
endPoint: .bottom
|
|
)
|
|
VisualEffectView(material: .hudWindow, blendingMode: .withinWindow)
|
|
.opacity(0.05)
|
|
}
|
|
.clipShape(Capsule())
|
|
}
|
|
|
|
private var statusView: some View {
|
|
RecorderStatusDisplay(
|
|
currentState: whisperState.recordingState,
|
|
audioMeter: recorder.audioMeter
|
|
)
|
|
}
|
|
|
|
var body: some View {
|
|
Group {
|
|
if windowManager.isVisible {
|
|
Capsule()
|
|
.fill(.clear)
|
|
.background(backgroundView)
|
|
.overlay {
|
|
Capsule()
|
|
.strokeBorder(Color.white.opacity(0.1), lineWidth: 0.5)
|
|
}
|
|
.overlay {
|
|
HStack(spacing: 0) {
|
|
if windowManager.isExpanded {
|
|
// Left button zone - only exists when expanded
|
|
RecorderPromptButton(showPopover: $showEnhancementPromptPopover)
|
|
.padding(.leading, 6)
|
|
.transition(.scale(scale: 0.5).combined(with: .opacity))
|
|
|
|
Spacer()
|
|
}
|
|
|
|
// Fixed visualizer zone - takes full width when compact
|
|
statusView
|
|
.frame(maxWidth: .infinity)
|
|
|
|
if windowManager.isExpanded {
|
|
Spacer()
|
|
|
|
// Right button zone - only exists when expanded
|
|
RecorderPowerModeButton(showPopover: $showPowerModePopover)
|
|
.padding(.trailing, 6)
|
|
.transition(.scale(scale: 0.5).combined(with: .opacity))
|
|
}
|
|
}
|
|
.padding(.vertical, 8)
|
|
}
|
|
.onHover { hovering in
|
|
isHovering = hovering
|
|
if hovering {
|
|
windowManager.expand()
|
|
} else {
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
|
|
// Only collapse if not hovering AND no popover is showing
|
|
if !isHovering && !isAnyPopoverShowing {
|
|
windowManager.collapse()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
// Set up the callback so WindowManager can check popover and hover state
|
|
windowManager.shouldPreventCollapse = {
|
|
isAnyPopoverShowing || isHovering
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|