fix: match provider picker to action popup
This commit is contained in:
@@ -15,7 +15,9 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
ActionEntry(title: "Copy Emoji", symbol: "doc.on.doc", color: SunsetPalette.text),
|
||||
ActionEntry(title: "Change source language…", symbol: "character.bubble", color: SunsetPalette.text),
|
||||
ActionEntry(title: "Change target language…", symbol: "character.bubble", color: SunsetPalette.text),
|
||||
ActionEntry(title: "Swap languages", symbol: "arrow.left.arrow.right", color: SunsetPalette.text)
|
||||
ActionEntry(title: "Swap languages", symbol: "arrow.left.arrow.right", color: SunsetPalette.text),
|
||||
ActionEntry(title: "MyMemory (no key)", symbol: "checkmark", color: SunsetPalette.text),
|
||||
ActionEntry(title: "OpenAI · gpt-6-luna", symbol: "checkmark", color: SunsetPalette.text)
|
||||
]
|
||||
private var visibleEntries: [Int] = []
|
||||
private var availableEntries = Array(0..<6)
|
||||
@@ -41,6 +43,8 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
var changeSourceLanguage: (() -> Void)?
|
||||
var changeTargetLanguage: (() -> Void)?
|
||||
var swapLanguages: (() -> Void)?
|
||||
var selectProvider: ((Bool) -> Void)?
|
||||
private var currentProviderEntry: Int?
|
||||
var closed: (() -> Void)?
|
||||
var isShown: Bool { viewIfLoaded?.superview != nil && !isClosing }
|
||||
|
||||
@@ -143,9 +147,22 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
searchAccessibilityLabel: "Search translation actions")
|
||||
}
|
||||
|
||||
func showProviders(selectedOpenAI: Bool, relativeTo anchor: NSView) {
|
||||
currentProviderEntry = selectedOpenAI ? 11 : 10
|
||||
show(title: "Translation provider", relativeTo: anchor, available: [10, 11],
|
||||
searchAccessibilityLabel: "Search translation providers", belowAnchor: true)
|
||||
if isShown {
|
||||
selectedEntry = currentProviderEntry
|
||||
updateSelection()
|
||||
}
|
||||
}
|
||||
|
||||
private func show(title: String, relativeTo anchor: NSView, available: [Int], emoji: Bool = false,
|
||||
searchAccessibilityLabel: String = "Search application actions") {
|
||||
if isShown { close(); return }
|
||||
searchAccessibilityLabel: String = "Search application actions", belowAnchor: Bool = false) {
|
||||
if viewIfLoaded?.superview != nil {
|
||||
if isShown, availableEntries == available { close(); return }
|
||||
close(animated: false)
|
||||
}
|
||||
guard let window = anchor.window, let host = window.contentView else { return }
|
||||
let pill = anchor.superview ?? anchor
|
||||
_ = view
|
||||
@@ -163,6 +180,13 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
])
|
||||
favorite.button.setAccessibilityLabel(favoriteTitle)
|
||||
favorite.icon.image = NSImage(systemSymbolName: isFavorite ? "star.fill" : "star", accessibilityDescription: nil)
|
||||
for index in [10, 11] {
|
||||
entries[index].icon.isHidden = currentProviderEntry != index
|
||||
}
|
||||
search.placeholderAttributedString = NSAttributedString(
|
||||
string: belowAnchor ? "Search for providers…" : "Search for actions…",
|
||||
attributes: [.foregroundColor: SunsetPalette.secondaryText,
|
||||
.font: NSFont.systemFont(ofSize: LauncherRowView.textSize)])
|
||||
search.stringValue = ""
|
||||
controlTextDidChange(Notification(name: NSControl.textDidChangeNotification))
|
||||
transitionGeneration += 1
|
||||
@@ -182,16 +206,18 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
])
|
||||
NSLayoutConstraint.activate([
|
||||
view.trailingAnchor.constraint(equalTo: pill.trailingAnchor),
|
||||
view.bottomAnchor.constraint(equalTo: pill.bottomAnchor)
|
||||
belowAnchor
|
||||
? view.topAnchor.constraint(equalTo: pill.bottomAnchor, constant: 8)
|
||||
: view.bottomAnchor.constraint(equalTo: pill.bottomAnchor)
|
||||
])
|
||||
coveredPill = pill
|
||||
coveredPill = belowAnchor ? nil : pill
|
||||
coveredPillAlpha = pill.alphaValue
|
||||
}
|
||||
pill.setAccessibilityHidden(true)
|
||||
coveredPill?.setAccessibilityHidden(true)
|
||||
NSAnimationContext.runAnimationGroup { context in
|
||||
context.duration = NSWorkspace.shared.accessibilityDisplayShouldReduceMotion ? 0 : 0.16
|
||||
view.animator().alphaValue = 1
|
||||
pill.animator().alphaValue = 0
|
||||
coveredPill?.animator().alphaValue = 0
|
||||
}
|
||||
window.makeFirstResponder(search)
|
||||
(search.currentEditor() as? NSTextView)?.insertionPointColor = SunsetPalette.accent
|
||||
@@ -271,7 +297,8 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
let selected = selectedEntry == index
|
||||
entries[index].view.isSelected = selected
|
||||
entries[index].returnKey.isHidden = !selected
|
||||
entries[index].button.setAccessibilityValue(selected ? "Selected" : "Not selected")
|
||||
let current = currentProviderEntry == index ? ", Current provider" : ""
|
||||
entries[index].button.setAccessibilityValue((selected ? "Selected" : "Not selected") + current)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +337,8 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
case 7: changeSourceLanguage?()
|
||||
case 8: changeTargetLanguage?()
|
||||
case 9: swapLanguages?()
|
||||
case 10: selectProvider?(false)
|
||||
case 11: selectProvider?(true)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import Security
|
||||
|
||||
@MainActor
|
||||
final class TranslationController: NSViewController {
|
||||
let providerPicker = NSPopUpButton()
|
||||
private let providerButton = NSButton(title: "", target: nil, action: nil)
|
||||
let providerControl = NSView()
|
||||
private let languageButton = NSButton(title: "", target: nil, action: nil)
|
||||
private let actionsButton = NSButton(title: "Actions", target: nil, action: nil)
|
||||
@@ -21,7 +21,7 @@ final class TranslationController: NSViewController {
|
||||
Locale(identifier: "en").localizedString(forLanguageCode: code) ?? code
|
||||
}
|
||||
private func languageName(_ code: String) -> String { Self.languageName(code) }
|
||||
private var usesMyMemory: Bool { providerPicker.indexOfSelectedItem == 0 }
|
||||
private var usesMyMemory: Bool
|
||||
private let output = NSTextView()
|
||||
private let settingsButton = NSButton(title: "Open Translate Settings", target: nil, action: nil)
|
||||
private let status = NSTextField(wrappingLabelWithString: "")
|
||||
@@ -52,6 +52,7 @@ final class TranslationController: NSViewController {
|
||||
self.myMemory = myMemory
|
||||
self.openAI = openAI
|
||||
self.pasteboard = pasteboard
|
||||
usesMyMemory = defaults.string(forKey: "translationProvider") != "openai"
|
||||
sourceLanguage = defaults.string(forKey: "translationSourceLanguage")
|
||||
.flatMap { Self.languages.contains($0) ? $0 : nil } ?? "en"
|
||||
targetLanguage = defaults.string(forKey: "translationTargetLanguage")
|
||||
@@ -63,30 +64,28 @@ final class TranslationController: NSViewController {
|
||||
|
||||
override func loadView() {
|
||||
view = NSView()
|
||||
providerPicker.addItems(withTitles: ["MyMemory (no key)", "OpenAI · gpt-6-luna"])
|
||||
providerPicker.selectItem(at: defaults.string(forKey: "translationProvider") == "openai" ? 1 : 0)
|
||||
providerPicker.setAccessibilityLabel("Translation provider")
|
||||
providerPicker.target = self
|
||||
providerPicker.action = #selector(providerChanged)
|
||||
providerPicker.isBordered = false
|
||||
(providerPicker.cell as? NSPopUpButtonCell)?.arrowPosition = .noArrow
|
||||
providerPicker.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
providerPicker.contentTintColor = SunsetPalette.text
|
||||
providerButton.title = usesMyMemory ? "MyMemory (no key)" : "OpenAI · gpt-6-luna"
|
||||
providerButton.setAccessibilityLabel("Translation provider")
|
||||
providerButton.target = self
|
||||
providerButton.action = #selector(showProviders)
|
||||
providerButton.isBordered = false
|
||||
providerButton.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
providerButton.contentTintColor = SunsetPalette.text
|
||||
let chevron = NSButton(image: NSImage(systemSymbolName: "chevron.down", accessibilityDescription: nil)!,
|
||||
target: providerPicker, action: #selector(NSControl.performClick(_:)))
|
||||
target: self, action: #selector(showProviders))
|
||||
chevron.isBordered = false
|
||||
chevron.contentTintColor = SunsetPalette.secondaryText
|
||||
chevron.setAccessibilityElement(false)
|
||||
stylePill(providerControl)
|
||||
for control in [providerPicker, chevron] {
|
||||
for control in [providerButton, chevron] {
|
||||
control.translatesAutoresizingMaskIntoConstraints = false
|
||||
providerControl.addSubview(control)
|
||||
}
|
||||
NSLayoutConstraint.activate([
|
||||
providerControl.heightAnchor.constraint(equalToConstant: 36),
|
||||
providerPicker.leadingAnchor.constraint(equalTo: providerControl.leadingAnchor, constant: 14),
|
||||
providerPicker.centerYAnchor.constraint(equalTo: providerControl.centerYAnchor),
|
||||
chevron.leadingAnchor.constraint(equalTo: providerPicker.trailingAnchor, constant: 8),
|
||||
providerButton.leadingAnchor.constraint(equalTo: providerControl.leadingAnchor, constant: 14),
|
||||
providerButton.centerYAnchor.constraint(equalTo: providerControl.centerYAnchor),
|
||||
chevron.leadingAnchor.constraint(equalTo: providerButton.trailingAnchor, constant: 8),
|
||||
chevron.centerYAnchor.constraint(equalTo: providerControl.centerYAnchor),
|
||||
chevron.trailingAnchor.constraint(equalTo: providerControl.trailingAnchor, constant: -12),
|
||||
chevron.widthAnchor.constraint(equalToConstant: 10),
|
||||
@@ -112,6 +111,7 @@ final class TranslationController: NSViewController {
|
||||
actions.changeSourceLanguage = { [weak self] in self?.chooseLanguage(source: true) }
|
||||
actions.changeTargetLanguage = { [weak self] in self?.chooseLanguage(source: false) }
|
||||
actions.swapLanguages = { [weak self] in self?.swapLanguages() }
|
||||
actions.selectProvider = { [weak self] in self?.selectProvider(openAI: $0) }
|
||||
settingsButton.target = self
|
||||
settingsButton.action = #selector(openSettings)
|
||||
settingsButton.isHidden = true
|
||||
@@ -196,6 +196,11 @@ final class TranslationController: NSViewController {
|
||||
pill.layer?.backgroundColor = SunsetPalette.background.withAlphaComponent(0.25).cgColor
|
||||
}
|
||||
|
||||
@objc func showProviders() {
|
||||
actions.showProviders(selectedOpenAI: !usesMyMemory, relativeTo: providerButton)
|
||||
translateButton.keyEquivalent = actions.isShown ? "" : "\r"
|
||||
}
|
||||
|
||||
@objc func showActions() {
|
||||
actions.showTranslation(relativeTo: actionsButton)
|
||||
translateButton.keyEquivalent = actions.isShown ? "" : "\r"
|
||||
@@ -267,8 +272,12 @@ final class TranslationController: NSViewController {
|
||||
setStatus("")
|
||||
}
|
||||
|
||||
@objc private func providerChanged() {
|
||||
defaults.set(usesMyMemory ? "mymemory" : "openai", forKey: "translationProvider")
|
||||
func selectProvider(openAI: Bool) {
|
||||
let newUsesMyMemory = !openAI
|
||||
guard newUsesMyMemory != usesMyMemory else { return }
|
||||
usesMyMemory = newUsesMyMemory
|
||||
providerButton.title = usesMyMemory ? "MyMemory (no key)" : "OpenAI · gpt-6-luna"
|
||||
defaults.set(openAI ? "openai" : "mymemory", forKey: "translationProvider")
|
||||
inputChanged()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user