diff --git a/VoiceInk.xcodeproj/project.pbxproj b/VoiceInk.xcodeproj/project.pbxproj index 9976323..b7ac59f 100644 --- a/VoiceInk.xcodeproj/project.pbxproj +++ b/VoiceInk.xcodeproj/project.pbxproj @@ -446,7 +446,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 136; + CURRENT_PROJECT_VERSION = 138; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_TEAM = V6J6A3VWY2; ENABLE_HARDENED_RUNTIME = YES; @@ -461,7 +461,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.36; + MARKETING_VERSION = 1.38; PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -479,7 +479,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 136; + CURRENT_PROJECT_VERSION = 138; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_TEAM = V6J6A3VWY2; ENABLE_HARDENED_RUNTIME = YES; @@ -494,7 +494,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.36; + MARKETING_VERSION = 1.38; PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/VoiceInk/Services/ImportExportService.swift b/VoiceInk/Services/ImportExportService.swift index 053e22a..7784e28 100644 --- a/VoiceInk/Services/ImportExportService.swift +++ b/VoiceInk/Services/ImportExportService.swift @@ -18,6 +18,7 @@ struct GeneralSettings: Codable { let isAutoCopyEnabled: Bool? let isSoundFeedbackEnabled: Bool? let isSystemMuteEnabled: Bool? + let isFallbackWindowEnabled: Bool? } struct VoiceInkExportedSettings: Codable { @@ -90,7 +91,8 @@ class ImportExportService { audioRetentionPeriod: UserDefaults.standard.integer(forKey: keyAudioRetentionPeriod), isAutoCopyEnabled: whisperState.isAutoCopyEnabled, isSoundFeedbackEnabled: soundManager.isEnabled, - isSystemMuteEnabled: mediaController.isSystemMuteEnabled + isSystemMuteEnabled: mediaController.isSystemMuteEnabled, + isFallbackWindowEnabled: UserDefaults.standard.object(forKey: "isFallbackWindowEnabled") == nil ? true : UserDefaults.standard.bool(forKey: "isFallbackWindowEnabled") ) let exportedSettings = VoiceInkExportedSettings( @@ -245,6 +247,9 @@ class ImportExportService { if let muteSystem = general.isSystemMuteEnabled { mediaController.isSystemMuteEnabled = muteSystem } + if let fallbackEnabled = general.isFallbackWindowEnabled { + UserDefaults.standard.set(fallbackEnabled, forKey: "isFallbackWindowEnabled") + } } self.showRestartAlert(message: "Settings imported successfully from \(url.lastPathComponent). All settings (including general app settings) have been applied.") diff --git a/VoiceInk/Views/Settings/SettingsView.swift b/VoiceInk/Views/Settings/SettingsView.swift index ca7bcee..d2b4770 100644 --- a/VoiceInk/Views/Settings/SettingsView.swift +++ b/VoiceInk/Views/Settings/SettingsView.swift @@ -14,6 +14,7 @@ struct SettingsView: View { @StateObject private var deviceManager = AudioDeviceManager.shared @ObservedObject private var mediaController = MediaController.shared @AppStorage("hasCompletedOnboarding") private var hasCompletedOnboarding = true + @AppStorage("isFallbackWindowEnabled") private var isFallbackWindowEnabled = true @State private var showResetOnboardingAlert = false @State private var currentShortcut = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder) @@ -73,7 +74,7 @@ struct SettingsView: View { SettingsSection( icon: "speaker.wave.2.bubble.left.fill", title: "Recording Feedback", - subtitle: "Customize audio and system feedback" + subtitle: "Customize app & system feedback" ) { VStack(alignment: .leading, spacing: 12) { Toggle(isOn: $whisperState.isAutoCopyEnabled) { @@ -94,6 +95,12 @@ struct SettingsView: View { } .toggleStyle(.switch) .help("Automatically mute system audio when recording starts and restore when recording stops") + + Toggle(isOn: $isFallbackWindowEnabled) { + Text("Show fallback window when paste fails") + } + .toggleStyle(.switch) + .help("Display a fallback window with the transcribed text when automatic pasting is not possible") } } diff --git a/VoiceInk/Whisper/WhisperState.swift b/VoiceInk/Whisper/WhisperState.swift index c658f1e..67d4bd1 100644 --- a/VoiceInk/Whisper/WhisperState.swift +++ b/VoiceInk/Whisper/WhisperState.swift @@ -382,8 +382,10 @@ class WhisperState: NSObject, ObservableObject, AVAudioRecorderDelegate { ClipboardManager.copyToClipboard(text) } - if !PasteEligibilityService.isPastePossible() { - TranscriptionFallbackManager.shared.showFallback(for: text) + if !PasteEligibilityService.isPastePossible() && (UserDefaults.standard.object(forKey: "isFallbackWindowEnabled") == nil ? true : UserDefaults.standard.bool(forKey: "isFallbackWindowEnabled")) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + TranscriptionFallbackManager.shared.showFallback(for: text) + } } } try? FileManager.default.removeItem(at: url) @@ -485,8 +487,10 @@ class WhisperState: NSObject, ObservableObject, AVAudioRecorderDelegate { ClipboardManager.copyToClipboard(textToPaste) } - if !PasteEligibilityService.isPastePossible() { - TranscriptionFallbackManager.shared.showFallback(for: textToPaste) + if !PasteEligibilityService.isPastePossible() && (UserDefaults.standard.object(forKey: "isFallbackWindowEnabled") == nil ? true : UserDefaults.standard.bool(forKey: "isFallbackWindowEnabled")) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + TranscriptionFallbackManager.shared.showFallback(for: textToPaste) + } } } }