fix: preserve uncommitted translation input

This commit is contained in:
2026-10-25 15:44:44 +01:00
parent 47912d237c
commit ef979d2838
5 changed files with 96 additions and 5 deletions
@@ -37,6 +37,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
private var launcherViews: [NSView] = []
private var launcherFrameBeforeReview: NSRect?
private var translation: TranslationController?
private var translationDraft: TranslationController.Draft?
private var emojiPicker: EmojiPickerController?
private var notes: NotesController?
private let notesDirectory: URL?
@@ -886,7 +887,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
let accessibilityLabel: String
switch command {
case .translate:
let tool = TranslationController(defaults: defaults, pasteboard: pasteboard)
let tool = TranslationController(defaults: defaults, pasteboard: pasteboard, draft: translationDraft)
tool.dismiss = { [weak self] in self?.dismiss() }
translation = tool
tool.input = { [weak self] in self?.searchField.stringValue ?? "" }
@@ -931,6 +932,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
guard let self, let controller else { return }
controller.view.removeFromSuperview()
self.translation?.providerControl.removeFromSuperview()
if let translation = self.translation { self.translationDraft = translation.draft }
self.translationHeader.isHidden = true
self.translation = nil
self.emojiPicker = nil
@@ -976,7 +978,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
commandBack.target = self
commandBack.action = #selector(goBackCommand)
commandBack.isHidden = false
searchField.stringValue = ""
searchField.stringValue = command == .translate ? translationDraft?.input ?? "" : ""
searchField.placeholderAttributedString = NSAttributedString(
string: placeholder,
attributes: previousPlaceholder?.attributes(at: 0, effectiveRange: nil) ?? [:]
@@ -1011,6 +1013,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
content.addSubview(controller.view)
if let translation {
translationHeader.addArrangedSubview(translation.providerControl)
commandBack.setAccessibilityLabel(translation.backAccessibilityLabel)
commandBack.toolTip = translation.backAccessibilityLabel
translationHeader.isHidden = false
}
NSLayoutConstraint.activate([
+13 -1
View File
@@ -32,6 +32,14 @@ final class TranslationController: NSViewController {
private func languageName(_ code: String) -> String { Self.languageName(code) }
private var usesMyMemory: Bool
private var textToTranslate: String?
struct Draft {
let input: String
let textToTranslate: String?
}
private var committed = false
var draft: Draft? {
committed ? nil : Draft(input: input?() ?? "", textToTranslate: textToTranslate)
}
private let sourcePreview = NSTextField(wrappingLabelWithString: "")
private let output = NSTextView()
private let settingsButton = NSButton(title: "Open Translate Settings", target: nil, action: nil)
@@ -60,13 +68,15 @@ final class TranslationController: NSViewController {
openAI: @escaping @MainActor (String, String, String, String, String) async throws -> String = {
try await TranslationAPI.translate($0, apiKey: $3, sourceLanguage: $1, targetLanguage: $2, context: $4)
},
pasteboard: NSPasteboard = .general
pasteboard: NSPasteboard = .general,
draft: Draft? = nil
) {
self.defaults = defaults
self.credentialsStore = credentials
self.myMemory = myMemory
self.openAI = openAI
self.pasteboard = pasteboard
textToTranslate = draft?.textToTranslate
usesMyMemory = defaults.string(forKey: "translationProvider") != "openai"
sourceLanguage = defaults.string(forKey: "translationSourceLanguage")
.flatMap { Self.languages.contains($0) ? $0 : nil } ?? "en"
@@ -285,6 +295,7 @@ final class TranslationController: NSViewController {
}
func inputChanged() {
committed = false
cancelRequest()
output.string = ""
outputSecondaryRange = nil
@@ -354,6 +365,7 @@ final class TranslationController: NSViewController {
}
pasteboard.clearContents()
if pasteboard.setString(output.string, forType: .string) {
committed = true
dismiss?()
} else {
setStatus("Could not copy the translation. Try again.", isError: true)