import SwiftUI import KeyboardShortcuts import AppKit struct RecordView: View { @EnvironmentObject var whisperState: WhisperState @EnvironmentObject var hotkeyManager: HotkeyManager @Environment(\.colorScheme) private var colorScheme @ObservedObject private var mediaController = MediaController.shared private var hasShortcutSet: Bool { KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder) != nil } var body: some View { ScrollView(showsIndicators: false) { mainContent } .background(Color(.controlBackgroundColor).opacity(0.5)) } private var mainContent: some View { VStack(spacing: 48) { heroSection controlsSection } .padding(32) } private var heroSection: some View { VStack(spacing: 20) { appIconView titleSection } } private var appIconView: some View { ZStack { Circle() .fill(Color.accentColor.opacity(0.15)) .frame(width: 160, height: 160) .blur(radius: 30) if let image = NSImage(named: "AppIcon") { Image(nsImage: image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 120, height: 120) .cornerRadius(30) .overlay( RoundedRectangle(cornerRadius: 30) .stroke(.white.opacity(0.2), lineWidth: 1) ) .shadow(color: .accentColor.opacity(0.3), radius: 20) } } } private var titleSection: some View { VStack(spacing: 8) { Text("VOICEINK") .font(.system(size: 42, weight: .bold)) if whisperState.currentModel != nil { Text("Powered by Whisper AI") .font(.system(size: 15)) .foregroundColor(.secondary) } } } private var controlsSection: some View { VStack(spacing: 32) { compactControlsCard instructionsCard } } private var compactControlsCard: some View { HStack(spacing: 32) { shortcutSection if hasShortcutSet { Divider() .frame(height: 40) pushToTalkSection Divider() .frame(height: 40) // Settings section VStack(alignment: .leading, spacing: 12) { Toggle(isOn: $whisperState.isAutoCopyEnabled) { HStack { Image(systemName: "doc.on.clipboard") .foregroundColor(.secondary) Text("Auto-copy to clipboard") .font(.subheadline.weight(.medium)) } } .toggleStyle(.switch) Toggle(isOn: .init( get: { SoundManager.shared.isEnabled }, set: { SoundManager.shared.isEnabled = $0 } )) { HStack { Image(systemName: "speaker.wave.2") .foregroundColor(.secondary) Text("Sound feedback") .font(.subheadline.weight(.medium)) } } .toggleStyle(.switch) Toggle(isOn: $mediaController.isMediaPauseEnabled) { HStack { Image(systemName: "play.slash") .foregroundColor(.secondary) Text("Pause media during recording") .font(.subheadline.weight(.medium)) } } .toggleStyle(.switch) .help("Automatically pause music playback when recording starts and resume when recording stops") } } } .padding(24) } private var shortcutSection: some View { VStack(spacing: 12) { if hasShortcutSet { if let shortcut = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder) { KeyboardShortcutView(shortcut: shortcut) .scaleEffect(1.2) } } else { Image(systemName: "keyboard.badge.exclamationmark") .font(.system(size: 28)) .foregroundColor(.orange) } Button(action: { NotificationCenter.default.post( name: .navigateToDestination, object: nil, userInfo: ["destination": "Settings"] ) }) { Text(hasShortcutSet ? "Change" : "Set Shortcut") .font(.subheadline.weight(.medium)) .foregroundColor(.accentColor) } .buttonStyle(.plain) } } private var pushToTalkSection: some View { VStack(alignment: .leading, spacing: 12) { Toggle(isOn: $hotkeyManager.isPushToTalkEnabled) { Text("Push-to-Talk") .font(.subheadline.weight(.medium)) } .toggleStyle(.switch) if hotkeyManager.isPushToTalkEnabled { pushToTalkOptions } } } private var pushToTalkOptions: some View { VStack(alignment: .leading, spacing: 8) { PushToTalkKeySelector(selectedKey: $hotkeyManager.pushToTalkKey) HStack(spacing: 6) { Image(systemName: "arrow.left.arrow.right.circle.fill") .foregroundColor(.secondary) .font(.system(size: 12)) Text("Click to switch") .font(.caption) .foregroundColor(.secondary) } } } private var instructionsCard: some View { VStack(alignment: .leading, spacing: 28) { Text("How it works") .font(.title3.weight(.bold)) VStack(alignment: .leading, spacing: 24) { ForEach(getInstructions(), id: \.title) { instruction in InstructionRow(instruction: instruction) } Divider() .padding(.vertical, 4) afterRecordingSection } } .padding(28) .background( RoundedRectangle(cornerRadius: 16) .fill(Color(.windowBackgroundColor).opacity(0.4)) ) } private var afterRecordingSection: some View { VStack(alignment: .leading, spacing: 16) { Text("After recording") .font(.headline) VStack(alignment: .leading, spacing: 12) { InfoRow(icon: "doc.on.clipboard", text: "Copied to clipboard") InfoRow(icon: "text.cursor", text: "Pasted at cursor position") } } } private func getInstructions() -> [(icon: String, title: String, description: String)] { let keyName: String switch hotkeyManager.pushToTalkKey { case .rightOption: keyName = "right Option (⌥)" case .fn: keyName = "Fn" case .rightCommand: keyName = "right Command (⌘)" case .rightShift: keyName = "right Shift (⇧)" } let activateDescription = hotkeyManager.isPushToTalkEnabled ? "Hold the \(keyName) key" : "Press your configured shortcut" let finishDescription = hotkeyManager.isPushToTalkEnabled ? "Release the \(keyName) key to stop and process" : "Press the shortcut again to stop" return [ ( icon: "mic.circle.fill", title: "Start Recording", description: activateDescription ), ( icon: "waveform", title: "Speak Clearly", description: "Talk into your microphone naturally" ), ( icon: "stop.circle.fill", title: "Finish Up", description: finishDescription ) ] } } // Simplified InstructionRow struct InstructionRow: View { let instruction: (icon: String, title: String, description: String) var body: some View { HStack(alignment: .top, spacing: 16) { Image(systemName: instruction.icon) .font(.system(size: 20)) .foregroundColor(.accentColor) .frame(width: 24) VStack(alignment: .leading, spacing: 4) { Text(instruction.title) .font(.subheadline.weight(.medium)) Text(instruction.description) .font(.subheadline) .foregroundColor(.secondary) .fixedSize(horizontal: false, vertical: true) } } } } // Simplified InfoRow struct InfoRow: View { let icon: String let text: String var body: some View { HStack(spacing: 12) { Image(systemName: icon) .font(.system(size: 14)) .foregroundColor(.secondary) Text(text) .font(.subheadline) .foregroundColor(.secondary) } } }