Preserve transcription in clipboard by default, add restore option with configurable delay

This commit is contained in:
Beingpax 2025-12-07 15:24:10 +05:45
parent 45dbd57722
commit baae439aae
3 changed files with 60 additions and 20 deletions

View File

@ -5,12 +5,11 @@ class CursorPaster {
static func pasteAtCursor(_ text: String) { static func pasteAtCursor(_ text: String) {
let pasteboard = NSPasteboard.general let pasteboard = NSPasteboard.general
let preserveTranscript = UserDefaults.standard.bool(forKey: "preserveTranscriptInClipboard") let shouldRestoreClipboard = UserDefaults.standard.bool(forKey: "restoreClipboardAfterPaste")
var savedContents: [(NSPasteboard.PasteboardType, Data)] = [] var savedContents: [(NSPasteboard.PasteboardType, Data)] = []
// Only save clipboard contents if we plan to restore them if shouldRestoreClipboard {
if !preserveTranscript {
let currentItems = pasteboard.pasteboardItems ?? [] let currentItems = pasteboard.pasteboardItems ?? []
for item in currentItems { for item in currentItems {
@ -22,7 +21,7 @@ class CursorPaster {
} }
} }
ClipboardManager.setClipboard(text, transient: !preserveTranscript) ClipboardManager.setClipboard(text, transient: shouldRestoreClipboard)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
if UserDefaults.standard.bool(forKey: "UseAppleScriptPaste") { if UserDefaults.standard.bool(forKey: "UseAppleScriptPaste") {
@ -32,8 +31,11 @@ class CursorPaster {
} }
} }
if !preserveTranscript { if shouldRestoreClipboard {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { let restoreDelay = UserDefaults.standard.double(forKey: "clipboardRestoreDelay")
let delay = restoreDelay > 0 ? restoreDelay : 1.5
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
if !savedContents.isEmpty { if !savedContents.isEmpty {
pasteboard.clearContents() pasteboard.clearContents()
for (type, data) in savedContents { for (type, data) in savedContents {

View File

@ -24,6 +24,8 @@ struct GeneralSettings: Codable {
let isPauseMediaEnabled: Bool? let isPauseMediaEnabled: Bool?
let isTextFormattingEnabled: Bool? let isTextFormattingEnabled: Bool?
let isExperimentalFeaturesEnabled: Bool? let isExperimentalFeaturesEnabled: Bool?
let restoreClipboardAfterPaste: Bool?
let clipboardRestoreDelay: Double?
} }
struct VoiceInkExportedSettings: Codable { struct VoiceInkExportedSettings: Codable {
@ -103,7 +105,9 @@ class ImportExportService {
isSystemMuteEnabled: mediaController.isSystemMuteEnabled, isSystemMuteEnabled: mediaController.isSystemMuteEnabled,
isPauseMediaEnabled: playbackController.isPauseMediaEnabled, isPauseMediaEnabled: playbackController.isPauseMediaEnabled,
isTextFormattingEnabled: UserDefaults.standard.object(forKey: keyIsTextFormattingEnabled) as? Bool ?? true, isTextFormattingEnabled: UserDefaults.standard.object(forKey: keyIsTextFormattingEnabled) as? Bool ?? true,
isExperimentalFeaturesEnabled: UserDefaults.standard.bool(forKey: "isExperimentalFeaturesEnabled") isExperimentalFeaturesEnabled: UserDefaults.standard.bool(forKey: "isExperimentalFeaturesEnabled"),
restoreClipboardAfterPaste: UserDefaults.standard.bool(forKey: "restoreClipboardAfterPaste"),
clipboardRestoreDelay: UserDefaults.standard.double(forKey: "clipboardRestoreDelay")
) )
let exportedSettings = VoiceInkExportedSettings( let exportedSettings = VoiceInkExportedSettings(
@ -275,6 +279,12 @@ class ImportExportService {
if let textFormattingEnabled = general.isTextFormattingEnabled { if let textFormattingEnabled = general.isTextFormattingEnabled {
UserDefaults.standard.set(textFormattingEnabled, forKey: self.keyIsTextFormattingEnabled) UserDefaults.standard.set(textFormattingEnabled, forKey: self.keyIsTextFormattingEnabled)
} }
if let restoreClipboard = general.restoreClipboardAfterPaste {
UserDefaults.standard.set(restoreClipboard, forKey: "restoreClipboardAfterPaste")
}
if let clipboardDelay = general.clipboardRestoreDelay {
UserDefaults.standard.set(clipboardDelay, forKey: "clipboardRestoreDelay")
}
} }
self.showRestartAlert(message: "Settings imported successfully from \(url.lastPathComponent). All settings (including general app settings) have been applied.") self.showRestartAlert(message: "Settings imported successfully from \(url.lastPathComponent). All settings (including general app settings) have been applied.")

View File

@ -17,6 +17,8 @@ struct SettingsView: View {
@AppStorage("hasCompletedOnboarding") private var hasCompletedOnboarding = true @AppStorage("hasCompletedOnboarding") private var hasCompletedOnboarding = true
@AppStorage("autoUpdateCheck") private var autoUpdateCheck = true @AppStorage("autoUpdateCheck") private var autoUpdateCheck = true
@AppStorage("enableAnnouncements") private var enableAnnouncements = true @AppStorage("enableAnnouncements") private var enableAnnouncements = true
@AppStorage("restoreClipboardAfterPaste") private var restoreClipboardAfterPaste = false
@AppStorage("clipboardRestoreDelay") private var clipboardRestoreDelay = 1.5
@State private var showResetOnboardingAlert = false @State private var showResetOnboardingAlert = false
@State private var currentShortcut = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder) @State private var currentShortcut = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder)
@State private var isCustomCancelEnabled = false @State private var isCustomCancelEnabled = false
@ -174,9 +176,9 @@ struct SettingsView: View {
// Middle-Click Toggle // Middle-Click Toggle
VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 12) {
HStack(spacing: 8) { HStack(spacing: 8) {
Toggle("Enable Middle-Click Toggle", isOn: $hotkeyManager.isMiddleClickToggleEnabled.animation()) Toggle("Enable Middle-Click Toggle", isOn: $hotkeyManager.isMiddleClickToggleEnabled)
.toggleStyle(.switch) .toggleStyle(.switch)
InfoTip( InfoTip(
title: "Middle-Click Toggle", title: "Middle-Click Toggle",
message: "Use middle mouse button to toggle VoiceInk recording." message: "Use middle mouse button to toggle VoiceInk recording."
@ -188,7 +190,7 @@ struct SettingsView: View {
Text("Activation Delay") Text("Activation Delay")
.font(.system(size: 13, weight: .medium)) .font(.system(size: 13, weight: .medium))
.foregroundColor(.secondary) .foregroundColor(.secondary)
TextField("", value: $hotkeyManager.middleClickActivationDelay, formatter: { TextField("", value: $hotkeyManager.middleClickActivationDelay, formatter: {
let formatter = NumberFormatter() let formatter = NumberFormatter()
formatter.numberStyle = .none formatter.numberStyle = .none
@ -200,14 +202,13 @@ struct SettingsView: View {
.background(Color(NSColor.textBackgroundColor)) .background(Color(NSColor.textBackgroundColor))
.cornerRadius(5) .cornerRadius(5)
.frame(width: 70) .frame(width: 70)
Text("ms") Text("ms")
.foregroundColor(.secondary) .foregroundColor(.secondary)
Spacer() Spacer()
} }
.padding(.leading, 16) .padding(.leading, 16)
.transition(.opacity.combined(with: .move(edge: .top)))
} }
} }
} }
@ -258,14 +259,41 @@ struct SettingsView: View {
.toggleStyle(.switch) .toggleStyle(.switch)
.help("Automatically mute system audio when recording starts and restore when recording stops") .help("Automatically mute system audio when recording starts and restore when recording stops")
Toggle(isOn: Binding( VStack(alignment: .leading, spacing: 12) {
get: { UserDefaults.standard.bool(forKey: "preserveTranscriptInClipboard") }, HStack(spacing: 8) {
set: { UserDefaults.standard.set($0, forKey: "preserveTranscriptInClipboard") } Toggle("Restore clipboard after paste", isOn: $restoreClipboardAfterPaste)
)) { .toggleStyle(.switch)
Text("Preserve transcript in clipboard")
InfoTip(
title: "Restore Clipboard",
message: "When enabled, VoiceInk will restore your original clipboard content after pasting the transcription."
)
}
if restoreClipboardAfterPaste {
HStack(spacing: 8) {
Text("Restore Delay")
.font(.system(size: 13, weight: .medium))
.foregroundColor(.secondary)
Picker("", selection: $clipboardRestoreDelay) {
Text("0.5s").tag(0.5)
Text("1.0s").tag(1.0)
Text("1.5s").tag(1.5)
Text("2.0s").tag(2.0)
Text("2.5s").tag(2.5)
Text("3.0s").tag(3.0)
Text("4.0s").tag(4.0)
Text("5.0s").tag(5.0)
}
.pickerStyle(.menu)
.frame(width: 90)
Spacer()
}
.padding(.leading, 16)
}
} }
.toggleStyle(.switch)
.help("Keep the transcribed text in clipboard instead of restoring the original clipboard content")
} }
} }