feat: add searchable emoji picker
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
import AppKit
|
||||
import ConjureKit
|
||||
|
||||
@MainActor
|
||||
final class EmojiPickerController: NSViewController, NSCollectionViewDataSource {
|
||||
private let collection = NSCollectionView()
|
||||
private let category = NSPopUpButton()
|
||||
private let status = NSTextField(labelWithString: "")
|
||||
private let empty = NSTextField(labelWithString: "No matching emoji")
|
||||
private let copyButton = NSButton(title: "Copy Emoji", target: nil, action: nil)
|
||||
private let defaults: UserDefaults
|
||||
private let pasteboard: NSPasteboard
|
||||
private var results: [Emoji] = []
|
||||
private var selected = 0
|
||||
var input: (() -> String)?
|
||||
var closed: (() -> Void)?
|
||||
var copied: (() -> Void)?
|
||||
|
||||
init(defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general) {
|
||||
self.defaults = defaults
|
||||
self.pasteboard = pasteboard
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) { fatalError("Conjure creates its emoji picker programmatically") }
|
||||
|
||||
override func loadView() {
|
||||
view = NSView()
|
||||
category.addItems(withTitles: ["All Emoji", "Recently Used"] + EmojiCatalog.categories)
|
||||
category.setAccessibilityLabel("Emoji category")
|
||||
category.target = self
|
||||
category.action = #selector(categoryChanged)
|
||||
let layout = NSCollectionViewFlowLayout()
|
||||
layout.itemSize = NSSize(width: 64, height: 56)
|
||||
layout.minimumInteritemSpacing = 6
|
||||
layout.minimumLineSpacing = 6
|
||||
layout.sectionInset = NSEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
|
||||
collection.collectionViewLayout = layout
|
||||
collection.backgroundColors = [.clear]
|
||||
collection.dataSource = self
|
||||
collection.register(EmojiItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("emoji"))
|
||||
collection.setAccessibilityLabel("Emoji grid")
|
||||
let scroll = LauncherScrollView()
|
||||
scroll.documentView = collection
|
||||
scroll.hasVerticalScroller = true
|
||||
scroll.autohidesScrollers = true
|
||||
scroll.scrollerStyle = .overlay
|
||||
scroll.drawsBackground = false
|
||||
scroll.contentView.drawsBackground = false
|
||||
empty.textColor = SunsetPalette.secondaryText
|
||||
status.font = .systemFont(ofSize: 12)
|
||||
status.textColor = SunsetPalette.secondaryText
|
||||
status.lineBreakMode = .byTruncatingTail
|
||||
status.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
copyButton.target = self
|
||||
copyButton.action = #selector(copySelection)
|
||||
copyButton.keyEquivalent = "\r"
|
||||
copyButton.isBordered = false
|
||||
copyButton.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
copyButton.contentTintColor = SunsetPalette.text
|
||||
let footer = NSStackView(views: [status, NSView(), copyButton, ShortcutIndicator("↵")])
|
||||
footer.spacing = 8
|
||||
for child in [category, scroll, empty, footer] {
|
||||
child.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(child)
|
||||
}
|
||||
NSLayoutConstraint.activate([
|
||||
category.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
category.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
|
||||
scroll.topAnchor.constraint(equalTo: category.bottomAnchor, constant: 4),
|
||||
scroll.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
scroll.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
scroll.bottomAnchor.constraint(equalTo: footer.topAnchor, constant: -4),
|
||||
empty.centerXAnchor.constraint(equalTo: scroll.centerXAnchor),
|
||||
empty.centerYAnchor.constraint(equalTo: scroll.centerYAnchor),
|
||||
footer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
|
||||
footer.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
|
||||
footer.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8),
|
||||
footer.heightAnchor.constraint(equalToConstant: 36),
|
||||
])
|
||||
inputChanged()
|
||||
}
|
||||
|
||||
@objc private func categoryChanged() { inputChanged() }
|
||||
@objc func goBack() { closed?() }
|
||||
override func cancelOperation(_ sender: Any?) { goBack() }
|
||||
|
||||
func inputChanged() {
|
||||
let recent = defaults.stringArray(forKey: "recentEmoji") ?? []
|
||||
let matches = EmojiCatalog.search(input?() ?? "", category: category.indexOfSelectedItem > 1 ? category.titleOfSelectedItem : nil)
|
||||
if category.indexOfSelectedItem == 1 {
|
||||
results = recent.compactMap { value in matches.first { $0.value == value } }
|
||||
} else if category.indexOfSelectedItem == 0, (input?() ?? "").isEmpty {
|
||||
let recentSet = Set(recent)
|
||||
results = recent.compactMap { value in matches.first { $0.value == value } }
|
||||
+ matches.filter { !recentSet.contains($0.value) }
|
||||
} else {
|
||||
results = matches
|
||||
}
|
||||
selected = 0
|
||||
collection.reloadData()
|
||||
collection.scroll(NSPoint.zero)
|
||||
updateSelection()
|
||||
}
|
||||
|
||||
func moveSelection(by offset: Int) {
|
||||
guard !results.isEmpty else { return }
|
||||
let old = selected
|
||||
selected = min(max(selected + offset, 0), results.count - 1)
|
||||
(collection.item(at: IndexPath(item: old, section: 0)) as? EmojiItem)?.highlight(false)
|
||||
updateSelection()
|
||||
collection.scrollToItems(at: [IndexPath(item: selected, section: 0)], scrollPosition: .nearestVerticalEdge)
|
||||
}
|
||||
|
||||
func handle(_ selector: Selector) -> Bool {
|
||||
let columns = max(1, Int((collection.bounds.width - 32 + 6) / 70))
|
||||
switch selector {
|
||||
case #selector(NSResponder.moveLeft(_:)): moveSelection(by: -1)
|
||||
case #selector(NSResponder.moveRight(_:)): moveSelection(by: 1)
|
||||
case #selector(NSResponder.moveUp(_:)): moveSelection(by: -columns)
|
||||
case #selector(NSResponder.moveDown(_:)): moveSelection(by: columns)
|
||||
case #selector(NSResponder.insertNewline(_:)): copySelection()
|
||||
case #selector(NSResponder.cancelOperation(_:)): goBack()
|
||||
default: return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private func updateSelection() {
|
||||
empty.isHidden = !results.isEmpty
|
||||
if results.isEmpty {
|
||||
empty.stringValue = category.indexOfSelectedItem == 1 ? "No recently used emoji match" : "No matching emoji"
|
||||
}
|
||||
copyButton.isEnabled = !results.isEmpty
|
||||
status.stringValue = results.isEmpty ? "0 emoji" : "\(results[selected].name) · \(results.count) emoji"
|
||||
(collection.item(at: IndexPath(item: selected, section: 0)) as? EmojiItem)?.highlight(true)
|
||||
}
|
||||
|
||||
@objc func copySelection() {
|
||||
guard results.indices.contains(selected) else { return }
|
||||
let value = results[selected].value
|
||||
pasteboard.clearContents()
|
||||
guard pasteboard.setString(value, forType: .string) else {
|
||||
status.stringValue = "Couldn’t copy emoji. Try again."
|
||||
return
|
||||
}
|
||||
var recent = defaults.stringArray(forKey: "recentEmoji") ?? []
|
||||
recent.removeAll { $0 == value }
|
||||
defaults.set(Array(([value] + recent).prefix(30)), forKey: "recentEmoji")
|
||||
closed?()
|
||||
copied?()
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { results.count }
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("emoji"), for: indexPath) as! EmojiItem
|
||||
let emoji = results[indexPath.item]
|
||||
item.button.title = emoji.value
|
||||
item.button.toolTip = emoji.name
|
||||
item.button.setAccessibilityLabel(emoji.name)
|
||||
item.highlight(indexPath.item == selected)
|
||||
item.clicked = { [weak self] in
|
||||
self?.selected = indexPath.item
|
||||
self?.copySelection()
|
||||
}
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class EmojiItem: NSCollectionViewItem {
|
||||
let button = NSButton()
|
||||
var clicked: (() -> Void)?
|
||||
|
||||
override func loadView() {
|
||||
button.font = .systemFont(ofSize: 32)
|
||||
button.isBordered = false
|
||||
button.target = self
|
||||
button.action = #selector(copyEmoji)
|
||||
button.wantsLayer = true
|
||||
button.layer?.cornerRadius = 10
|
||||
view = button
|
||||
}
|
||||
|
||||
func highlight(_ selected: Bool) {
|
||||
button.layer?.backgroundColor = selected ? SunsetPalette.accent.withAlphaComponent(0.22).cgColor : nil
|
||||
button.setAccessibilitySelected(selected)
|
||||
}
|
||||
|
||||
@objc private func copyEmoji() { clicked?() }
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import ConjureKit
|
||||
final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSearchFieldDelegate, NSTableViewDataSource, NSTableViewDelegate {
|
||||
private let searchField = NSSearchField()
|
||||
private let searchSymbol = IconView(font: .systemFont(ofSize: 20))
|
||||
private let translationBack = NSButton(title: "", target: nil, action: nil)
|
||||
private let commandBack = NSButton(title: "", target: nil, action: nil)
|
||||
private let tableView = ApplicationTableView()
|
||||
private let statusLabel = NSTextField(labelWithString: "Finding applications…")
|
||||
private let emptyLabel = NSTextField(labelWithString: "Finding applications…")
|
||||
@@ -34,6 +34,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
private var launcherViews: [NSView] = []
|
||||
private var launcherFrameBeforeReview: NSRect?
|
||||
private var translation: TranslationController?
|
||||
private var emojiPicker: EmojiPickerController?
|
||||
private var isCommandOpen: Bool { translation != nil || emojiPicker != nil }
|
||||
|
||||
init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller()) {
|
||||
self.history = history
|
||||
@@ -61,13 +63,14 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
guard let self else { return }
|
||||
if let review = self.uninstallReview { review.moveSelection(offset) }
|
||||
else if self.actions.isShown { self.actions.moveSelection(by: offset) }
|
||||
else if let picker = self.emojiPicker { picker.moveSelection(by: offset) }
|
||||
else { self.moveSelection(by: offset) }
|
||||
}
|
||||
window.dismiss = { [weak self] in self?.dismiss() }
|
||||
window.canUseNumberShortcuts = { [weak self] in
|
||||
guard let self else { return false }
|
||||
return !self.isLaunching && self.calculation == nil && self.resultCount > 0
|
||||
&& self.launcherFrameBeforeReview == nil && !self.actions.isShown && self.translation == nil
|
||||
&& self.launcherFrameBeforeReview == nil && !self.actions.isShown && !self.isCommandOpen
|
||||
}
|
||||
window.numberHintsChanged = { [weak self] in self?.updateNumberHints() }
|
||||
window.launchNumber = { [weak self] index in
|
||||
@@ -98,7 +101,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
func present() {
|
||||
(window as? LauncherPanel)?.beginNumberHintSession()
|
||||
if launcherFrameBeforeReview != nil || translation != nil {
|
||||
if launcherFrameBeforeReview != nil || isCommandOpen {
|
||||
showWindow(nil)
|
||||
NSApp.activate()
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
@@ -134,8 +137,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
func dismiss(restoringFocus: Bool = true) {
|
||||
guard !restoringFocus || (!isLaunching && window?.attachedSheet == nil) else { return }
|
||||
if let review = uninstallReview { review.goBack(); return }
|
||||
if let translation {
|
||||
translation.goBack()
|
||||
if isCommandOpen {
|
||||
goBackCommand()
|
||||
if restoringFocus { return }
|
||||
}
|
||||
guard launcherFrameBeforeReview == nil else { return }
|
||||
@@ -230,18 +233,18 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
searchSymbol.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: nil)
|
||||
searchSymbol.contentTintColor = SunsetPalette.accent
|
||||
translationBack.image = IconStyle.symbol("chevron.left", for: searchFont)
|
||||
translationBack.imageScaling = .scaleProportionallyDown
|
||||
translationBack.isBordered = false
|
||||
translationBack.contentTintColor = SunsetPalette.secondaryText
|
||||
translationBack.setAccessibilityLabel("Back to applications")
|
||||
translationBack.toolTip = "Back to applications (Escape)"
|
||||
translationBack.isHidden = true
|
||||
commandBack.image = IconStyle.symbol("chevron.left", for: searchFont)
|
||||
commandBack.imageScaling = .scaleProportionallyDown
|
||||
commandBack.isBordered = false
|
||||
commandBack.contentTintColor = SunsetPalette.secondaryText
|
||||
commandBack.setAccessibilityLabel("Back to applications")
|
||||
commandBack.toolTip = "Back to applications (Escape)"
|
||||
commandBack.isHidden = true
|
||||
NSLayoutConstraint.activate([
|
||||
translationBack.widthAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)),
|
||||
translationBack.heightAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)),
|
||||
commandBack.widthAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)),
|
||||
commandBack.heightAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)),
|
||||
])
|
||||
let header = NSStackView(views: [searchSymbol, translationBack, searchField])
|
||||
let header = NSStackView(views: [searchSymbol, commandBack, searchField])
|
||||
header.orientation = .horizontal
|
||||
header.alignment = .centerY
|
||||
header.spacing = 12
|
||||
@@ -431,7 +434,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
|
||||
private func updateResults(preservingSelection: Bool = false, allowingCurrencyFetch: Bool = true) {
|
||||
guard translation == nil else { return }
|
||||
guard !isCommandOpen else { return }
|
||||
let selectedURL = preservingSelection && results.indices.contains(tableView.selectedRow)
|
||||
? results[tableView.selectedRow].id : nil
|
||||
let query = searchField.stringValue
|
||||
@@ -497,10 +500,12 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
func controlTextDidChange(_ notification: Notification) {
|
||||
if let translation { translation.inputChanged(); return }
|
||||
if let emojiPicker { emojiPicker.inputChanged(); return }
|
||||
updateResults()
|
||||
}
|
||||
|
||||
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
|
||||
if let emojiPicker { return emojiPicker.handle(commandSelector) }
|
||||
if let translation {
|
||||
if commandSelector == #selector(NSResponder.insertNewline(_:)) { translation.translate(); return true }
|
||||
if commandSelector == #selector(NSResponder.cancelOperation(_:)) { translation.goBack(); return true }
|
||||
@@ -524,7 +529,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
private var resultCount: Int { calculation == nil ? results.count : 1 }
|
||||
|
||||
private func moveSelection(by offset: Int) {
|
||||
guard translation == nil else { return }
|
||||
guard !isCommandOpen else { return }
|
||||
guard resultCount > 0 else { return }
|
||||
let row = min(max(tableView.selectedRow + offset, 0), resultCount - 1)
|
||||
tableView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
|
||||
@@ -532,7 +537,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
|
||||
private func updateOpenButton() {
|
||||
let canAct = !isLaunching && launcherFrameBeforeReview == nil && translation == nil && tableView.selectedRow >= 0
|
||||
let canAct = !isLaunching && launcherFrameBeforeReview == nil && !isCommandOpen && tableView.selectedRow >= 0
|
||||
openButton.title = calculation == nil
|
||||
? (results.indices.contains(tableView.selectedRow) && results[tableView.selectedRow].command != nil
|
||||
? "Open Command" : "Open Application") : "Copy Answer"
|
||||
@@ -584,9 +589,9 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
cell.locationLabel.isHidden = true
|
||||
cell.kindLabel.attributedStringValue = history.isFavorite(entry)
|
||||
? ApplicationCell.favoriteCommandKind : ApplicationCell.commandKind
|
||||
cell.imageView?.image = NSImage(systemSymbolName: "character.bubble", accessibilityDescription: nil)
|
||||
cell.imageView?.image = NSImage(systemSymbolName: entry.command == .emoji ? "face.smiling" : "character.bubble", accessibilityDescription: nil)
|
||||
cell.imageView?.contentTintColor = SunsetPalette.accent
|
||||
cell.toolTip = "Translate English to Japanese"
|
||||
cell.toolTip = entry.command == .emoji ? "Search and copy emoji" : "Translate English to Japanese"
|
||||
} else {
|
||||
let application = results[row]
|
||||
cell.textField?.stringValue = application.name
|
||||
@@ -616,7 +621,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
private func configureNumberHint(_ cell: ApplicationCell, row: Int, animated: Bool = false) {
|
||||
let visible = (window as? LauncherPanel)?.numberHintsVisible == true
|
||||
&& calculation == nil && row < 9 && row < resultCount && translation == nil
|
||||
&& calculation == nil && row < 9 && row < resultCount && !isCommandOpen
|
||||
cell.setNumberHint(visible ? String(row + 1) : nil, animated: animated)
|
||||
cell.setAccessibilityHelp(visible ? "Command-\(row + 1) opens this entry" : nil)
|
||||
}
|
||||
@@ -639,7 +644,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
@objc private func showActions() {
|
||||
guard !isLaunching, launcherFrameBeforeReview == nil, window?.attachedSheet == nil, results.indices.contains(tableView.selectedRow) else { return }
|
||||
guard translation == nil else { return }
|
||||
guard !isCommandOpen else { return }
|
||||
(window as? LauncherPanel)?.resetNumberHints()
|
||||
let application = results[tableView.selectedRow]
|
||||
actions.open = { [weak self] in self?.openApplication(application) }
|
||||
@@ -727,7 +732,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
|
||||
@objc private func openSelection() {
|
||||
guard !isLaunching, translation == nil, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
|
||||
guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
|
||||
if let calculation {
|
||||
guard tableView.selectedRow == 0, let value = calculation.copyValue else { return }
|
||||
let pasteboard = NSPasteboard.general
|
||||
@@ -753,11 +758,9 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
|
||||
private func openApplication(_ application: Application) {
|
||||
guard !isLaunching, translation == nil, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
|
||||
guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
|
||||
if let command = application.command {
|
||||
switch command {
|
||||
case .translate: showTranslation()
|
||||
}
|
||||
showCommand(command)
|
||||
history.recordLaunch(of: application)
|
||||
return
|
||||
}
|
||||
@@ -781,19 +784,42 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
}
|
||||
|
||||
private func showTranslation() {
|
||||
guard translation == nil, let content = window?.contentView else { return }
|
||||
let controller = TranslationController()
|
||||
translation = controller
|
||||
controller.input = { [weak self] in self?.searchField.stringValue ?? "" }
|
||||
@objc private func goBackCommand() {
|
||||
translation?.goBack()
|
||||
emojiPicker?.goBack()
|
||||
}
|
||||
|
||||
private func showCommand(_ command: Application.Command) {
|
||||
guard !isCommandOpen, let content = window?.contentView else { return }
|
||||
let controller: NSViewController
|
||||
let placeholder: String
|
||||
let accessibilityLabel: String
|
||||
switch command {
|
||||
case .translate:
|
||||
let tool = TranslationController()
|
||||
translation = tool
|
||||
tool.input = { [weak self] in self?.searchField.stringValue ?? "" }
|
||||
controller = tool
|
||||
placeholder = "Enter English text to translate…"
|
||||
accessibilityLabel = "English text to translate into Japanese"
|
||||
case .emoji:
|
||||
let tool = EmojiPickerController()
|
||||
emojiPicker = tool
|
||||
tool.input = { [weak self] in self?.searchField.stringValue ?? "" }
|
||||
tool.copied = { [weak self] in self?.dismiss() }
|
||||
controller = tool
|
||||
placeholder = "Search emoji by name or :shortcode:…"
|
||||
accessibilityLabel = "Search emoji"
|
||||
}
|
||||
let previousQuery = searchField.stringValue
|
||||
let previousPlaceholder = searchField.placeholderAttributedString
|
||||
controller.closed = { [weak self, weak controller] in
|
||||
let close: () -> Void = { [weak self, weak controller] in
|
||||
guard let self, let controller else { return }
|
||||
controller.view.removeFromSuperview()
|
||||
self.translation = nil
|
||||
self.translationBack.isHidden = true
|
||||
self.translationBack.target = nil
|
||||
self.emojiPicker = nil
|
||||
self.commandBack.isHidden = true
|
||||
self.commandBack.target = nil
|
||||
self.searchSymbol.isHidden = false
|
||||
for view in self.launcherViews.dropFirst() {
|
||||
view.isHidden = false
|
||||
@@ -807,19 +833,21 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
self.updateResults()
|
||||
self.window?.makeFirstResponder(self.searchField)
|
||||
}
|
||||
translation?.closed = close
|
||||
emojiPicker?.closed = close
|
||||
actions.close()
|
||||
(window as? LauncherPanel)?.resetNumberHints()
|
||||
openButton.keyEquivalent = ""
|
||||
searchSymbol.isHidden = true
|
||||
translationBack.target = controller
|
||||
translationBack.action = #selector(TranslationController.goBack)
|
||||
translationBack.isHidden = false
|
||||
commandBack.target = self
|
||||
commandBack.action = #selector(goBackCommand)
|
||||
commandBack.isHidden = false
|
||||
searchField.stringValue = ""
|
||||
searchField.placeholderAttributedString = NSAttributedString(
|
||||
string: "Enter English text to translate…",
|
||||
string: placeholder,
|
||||
attributes: previousPlaceholder?.attributes(at: 0, effectiveRange: nil) ?? [:]
|
||||
)
|
||||
searchField.setAccessibilityLabel("English text to translate into Japanese")
|
||||
searchField.setAccessibilityLabel(accessibilityLabel)
|
||||
for view in launcherViews.dropFirst() {
|
||||
view.isHidden = true
|
||||
view.setAccessibilityHidden(true)
|
||||
|
||||
Reference in New Issue
Block a user