Files
Grapp/src/SearchViewController.swift
2024-12-27 18:55:05 -08:00

176 lines
6.6 KiB
Swift

import AppKit
import OSLog
fileprivate enum ViewConstants {
static let spacing2: CGFloat = 2
static let spacing10: CGFloat = 10
static let spacing20: CGFloat = 20
static let spacing40: CGFloat = 40
}
class SearchViewController: NSViewController, NSTextFieldDelegate {
fileprivate static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier!,
category: String(describing: SearchViewController.self)
)
var foundProgram: Program? = nil
private var appIconImage: NSImageView = {
//let image = NSImageView(image: NSApp.applicationIconImage)
let image = NSImageView()
image.image = NSWorkspace.shared.icon(forFile: Bundle.main.bundlePath)
image.imageScaling = .scaleAxesIndependently
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
private var searchInput: EditableNSTextField = {
let textField = EditableNSTextField()
textField.placeholderString = "Search programs . . ."
textField.bezelStyle = .roundedBezel
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private var programsLabel: NSTextField = {
let textField = NSTextField()
textField.stringValue = ""
textField.isEditable = false
textField.isBezeled = false
textField.drawsBackground = false
textField.alignment = .left
textField.font = NSFont.systemFont(ofSize: NSFontDescriptor.preferredFontDescriptor(forTextStyle: .body).pointSize, weight: .bold)
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private var settingsButton: NSButton = {
let button = NSButton()
button.image = systemImage("gearshape.fill", .title2, .large, .init(paletteColors: [.white, .systemRed]))
button.isBordered = false
button.action = #selector(openSettings)
button.sizeToFit()
button.toolTip = "Quit"
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private func addSubviews() {
view.addSubview(appIconImage)
view.addSubview(searchInput)
view.addSubview(programsLabel)
view.addSubview(settingsButton)
}
private func setConstraints() {
NSLayoutConstraint.activate([
appIconImage.widthAnchor.constraint(equalToConstant: 70),
appIconImage.heightAnchor.constraint(equalTo: appIconImage.widthAnchor, multiplier: 1),
appIconImage.topAnchor.constraint(equalTo: view.topAnchor, constant: ViewConstants.spacing20),
appIconImage.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -ViewConstants.spacing10),
appIconImage.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: ViewConstants.spacing10),
searchInput.widthAnchor.constraint(equalToConstant: 300),
searchInput.topAnchor.constraint(equalTo: appIconImage.topAnchor),
searchInput.leadingAnchor.constraint(equalTo: appIconImage.trailingAnchor, constant: ViewConstants.spacing10),
settingsButton.firstBaselineAnchor.constraint(equalTo: searchInput.firstBaselineAnchor),
settingsButton.leadingAnchor.constraint(equalTo: searchInput.trailingAnchor, constant: ViewConstants.spacing10),
settingsButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -ViewConstants.spacing10),
programsLabel.topAnchor.constraint(equalTo: searchInput.bottomAnchor, constant: ViewConstants.spacing10),
programsLabel.leadingAnchor.constraint(equalTo: appIconImage.trailingAnchor, constant: ViewConstants.spacing10),
programsLabel.trailingAnchor.constraint(equalTo: searchInput.trailingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
searchInput.delegate = self
addSubviews()
setConstraints()
}
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.center()
}
override func loadView() {
self.view = NSView()
}
//private func fetchIcon() {
// for key in resultPaths.keys {
// }
//}
@objc
private func openSettings() {
}
func controlTextDidChange(_ obj: Notification) {
var list = ""
let programs = delegate.programs
for program in programs {
if program.name.lowercased().contains(searchInput.stringValue.lowercased()) {
if !list.isEmpty {
list += ", "
}
list += program.name + program.ext
foundProgram = program
break
} else {
foundProgram = nil
}
}
if let program = foundProgram {
programsLabel.stringValue = program.name + program.ext
let url = URL(fileURLWithPath: program.path).appendingPathComponent(program.name+program.ext)
appIconImage.image = NSWorkspace.shared.icon(forFile: url.path)
} else {
programsLabel.stringValue = ""
appIconImage.image = NSWorkspace.shared.icon(forFile: Bundle.main.bundlePath)
}
}
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if commandSelector == #selector(NSResponder.insertNewline(_:)) {
if let program = foundProgram {
let url = URL(fileURLWithPath: program.path).appendingPathComponent(program.name+program.ext)
let config = NSWorkspace.OpenConfiguration()
NSWorkspace.shared.openApplication(at: url, configuration: config, completionHandler: { [weak self] application, error in
if let error = error {
Self.logger.debug("Failed to open application: \(error.localizedDescription)")
} else {
Self.logger.debug("Application opened successfully")
DispatchQueue.main.async {
if let window = self?.view.window {
window.resignKey()
}
}
}
})
}
// TODO: Send this whenever SearchViewController becomes visible.
NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self)
return true
} else if commandSelector == #selector(NSResponder.insertTab(_:)) {
return true
}
return false
}
}