diff --git a/VoiceInk/PlaybackController.swift b/VoiceInk/PlaybackController.swift index 4d11502..b4dfd3b 100644 --- a/VoiceInk/PlaybackController.swift +++ b/VoiceInk/PlaybackController.swift @@ -3,8 +3,6 @@ import Combine import Foundation import SwiftUI import MediaRemoteAdapter - -/// Pauses media when recording starts, resumes when recording stops class PlaybackController: ObservableObject { static let shared = PlaybackController() private var mediaController: MediaRemoteAdapter.MediaController @@ -12,6 +10,7 @@ class PlaybackController: ObservableObject { private var isMediaPlaying = false private var lastKnownTrackInfo: TrackInfo? private var originalMediaAppBundleId: String? + @Published var isPauseMediaEnabled: Bool = UserDefaults.standard.bool(forKey: "isPauseMediaEnabled") { didSet { @@ -23,7 +22,7 @@ class PlaybackController: ObservableObject { mediaController = MediaRemoteAdapter.MediaController() if !UserDefaults.standard.contains(key: "isPauseMediaEnabled") { - UserDefaults.standard.set(true, forKey: "isPauseMediaEnabled") + UserDefaults.standard.set(false, forKey: "isPauseMediaEnabled") } mediaController.startListening() @@ -40,29 +39,47 @@ class PlaybackController: ObservableObject { } func pauseMedia() async { - guard isPauseMediaEnabled else { return } - - if isMediaPlaying { - wasPlayingWhenRecordingStarted = true - originalMediaAppBundleId = lastKnownTrackInfo?.payload.bundleIdentifier - mediaController.pause() - } else { - wasPlayingWhenRecordingStarted = false - originalMediaAppBundleId = nil + wasPlayingWhenRecordingStarted = false + originalMediaAppBundleId = nil + + guard isPauseMediaEnabled, + isMediaPlaying, + lastKnownTrackInfo?.payload.isPlaying == true, + let bundleId = lastKnownTrackInfo?.payload.bundleIdentifier else { + return } + + wasPlayingWhenRecordingStarted = true + originalMediaAppBundleId = bundleId + mediaController.pause() } func resumeMedia() async { - guard isPauseMediaEnabled, wasPlayingWhenRecordingStarted else { return } - - if let bundleId = originalMediaAppBundleId, isAppStillRunning(bundleId: bundleId) { - mediaController.play() + defer { + wasPlayingWhenRecordingStarted = false + originalMediaAppBundleId = nil } - originalMediaAppBundleId = nil + guard isPauseMediaEnabled, + wasPlayingWhenRecordingStarted, + let bundleId = originalMediaAppBundleId else { + return + } + + guard isAppStillRunning(bundleId: bundleId) else { + return + } + + guard let currentTrackInfo = lastKnownTrackInfo, + let currentBundleId = currentTrackInfo.payload.bundleIdentifier, + currentBundleId == bundleId, + currentTrackInfo.payload.isPlaying == false else { + return + } + + mediaController.play() } - /// Checks if an app with the given bundle identifier is currently running private func isAppStillRunning(bundleId: String) -> Bool { let runningApps = NSWorkspace.shared.runningApplications return runningApps.contains { $0.bundleIdentifier == bundleId } diff --git a/VoiceInk/Recorder.swift b/VoiceInk/Recorder.swift index a623c6d..582774f 100644 --- a/VoiceInk/Recorder.swift +++ b/VoiceInk/Recorder.swift @@ -152,8 +152,8 @@ class Recorder: ObservableObject { audioMeter = AudioMeter(averagePower: 0, peakPower: 0) Task { - // Complete system audio operations first await mediaController.unmuteSystemAudio() + try? await Task.sleep(nanoseconds: 100_000_000) await playbackController.resumeMedia() } deviceManager.isRecordingActive = false diff --git a/VoiceInk/Views/Settings/SettingsView.swift b/VoiceInk/Views/Settings/SettingsView.swift index 2201d2d..ac4aafc 100644 --- a/VoiceInk/Views/Settings/SettingsView.swift +++ b/VoiceInk/Views/Settings/SettingsView.swift @@ -3,7 +3,6 @@ import Cocoa import KeyboardShortcuts import LaunchAtLogin import AVFoundation -// Additional imports for Settings components struct SettingsView: View { @EnvironmentObject private var updaterViewModel: UpdaterViewModel @@ -23,7 +22,6 @@ struct SettingsView: View { var body: some View { ScrollView { VStack(spacing: 24) { - // Hotkey Selection Section SettingsSection( icon: "command.circle", title: "VoiceInk Shortcut", @@ -36,7 +34,6 @@ struct SettingsView: View { shortcutName: .toggleMiniRecorder ) - // Hotkey 2 Configuration (Conditional) if hotkeyManager.selectedHotkey2 != .none { Divider() hotkeyView( @@ -50,7 +47,6 @@ struct SettingsView: View { ) } - // "Add another hotkey" button if hotkeyManager.selectedHotkey1 != .none && hotkeyManager.selectedHotkey2 == .none { HStack { Spacer() @@ -71,7 +67,6 @@ struct SettingsView: View { Divider() - // Cancel Recording Override Toggle Toggle(isOn: $isCustomCancelEnabled) { Text("Override default double-tap Escape cancellation") } @@ -82,7 +77,6 @@ struct SettingsView: View { } } - // Show shortcut recorder only when override is enabled if isCustomCancelEnabled { HStack(spacing: 12) { Text("Custom Cancel Shortcut") @@ -123,7 +117,6 @@ struct SettingsView: View { } } - // Recording Feedback Section SettingsSection( icon: "speaker.wave.2.bubble.left.fill", title: "Recording Feedback", @@ -145,16 +138,15 @@ struct SettingsView: View { .help("Automatically mute system audio when recording starts and restore when recording stops") Toggle(isOn: $playbackController.isPauseMediaEnabled) { - Text("Pause media during recording") + Text("Pause media during recording (Experimental)") } .toggleStyle(.switch) - .help("Automatically pause active media playback when recording starts and resume when recording stops") + .help("Automatically pause active media playback when recording starts and resume when recording stops. This feature is experimental and may occasionally cause unexpected behavior.") } } - // Recorder Preference Section SettingsSection( icon: "rectangle.on.rectangle", title: "Recorder Style", @@ -173,7 +165,6 @@ struct SettingsView: View { } } - // Paste Method Section SettingsSection( icon: "doc.on.clipboard", title: "Paste Method", @@ -191,7 +182,6 @@ struct SettingsView: View { } } - // App Appearance Section SettingsSection( icon: "dock.rectangle", title: "App Appearance", @@ -206,7 +196,6 @@ struct SettingsView: View { } } - // Data & Privacy Section SettingsSection( icon: "lock.shield", title: "Data & Privacy", @@ -215,7 +204,6 @@ struct SettingsView: View { AudioCleanupSettingsView() } - // Startup Section SettingsSection( icon: "power", title: "Startup", @@ -230,7 +218,6 @@ struct SettingsView: View { } } - // Updates Section SettingsSection( icon: "arrow.triangle.2.circlepath", title: "Updates", @@ -249,7 +236,6 @@ struct SettingsView: View { } } - // Reset Onboarding Section SettingsSection( icon: "arrow.counterclockwise", title: "Reset Onboarding", @@ -267,7 +253,6 @@ struct SettingsView: View { } } - // Data Management Section SettingsSection( icon: "arrow.up.arrow.down.circle", title: "Data Management", @@ -320,7 +305,6 @@ struct SettingsView: View { } .background(Color(NSColor.controlBackgroundColor)) .onAppear { - // Initialize custom cancel shortcut state from stored preferences isCustomCancelEnabled = KeyboardShortcuts.getShortcut(for: .cancelRecorder) != nil } .alert("Reset Onboarding", isPresented: $showResetOnboardingAlert) {