Filesystem monitor and refactor.
This commit is contained in:
@@ -2,10 +2,9 @@ import AppKit
|
||||
import Carbon
|
||||
import ServiceManagement
|
||||
|
||||
class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
KeyDetectorButtonDelegate,
|
||||
NSTableViewDataSource, NSTableViewDelegate,
|
||||
PathsTableCellViewDelegate
|
||||
class SettingsViewController: NSViewController,
|
||||
NSTextFieldDelegate, KeyDetectorButtonDelegate, NSTableViewDataSource,
|
||||
NSTableViewDelegate, PathsTableCellViewDelegate
|
||||
{
|
||||
private var recording = false
|
||||
|
||||
@@ -14,6 +13,8 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
private var keyCode = Int(kVK_Space)
|
||||
private var modifiers = Int(optionKey)
|
||||
|
||||
private var paths: [String] = []
|
||||
|
||||
// NOTE: PERF: This is very slow to initialize because it creates a
|
||||
// a new process. This also cannot be done on a separate
|
||||
// thread. This sucks because the program now takes
|
||||
@@ -29,13 +30,22 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
|
||||
private var shortcutsLabel: NSTextField = {
|
||||
let textField = NSTextField(labelWithString: "Shortcut")
|
||||
textField.font = NSFont.systemFont(
|
||||
ofSize: NSFontDescriptor.preferredFontDescriptor(
|
||||
forTextStyle: .title2).pointSize, weight: .bold)
|
||||
textField.font = NSFont.systemFont(ofSize: NSFontDescriptor.preferredFontDescriptor(forTextStyle: .title2).pointSize, weight: .bold)
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
return textField
|
||||
}()
|
||||
|
||||
private var aboutButton: NSButton = {
|
||||
let button = NSButton()
|
||||
button.image = systemImage("info.circle.fill", .title2, .large, .init(paletteColors: [.white, .systemGray]))
|
||||
button.isBordered = false
|
||||
button.action = #selector(showAbout)
|
||||
button.sizeToFit()
|
||||
button.toolTip = "About"
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
return button
|
||||
}()
|
||||
|
||||
private var ctrlButton: NSButton = {
|
||||
let button = NSButton()
|
||||
button.title = "⌃"
|
||||
@@ -87,9 +97,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
textField.isBezeled = false
|
||||
textField.drawsBackground = false
|
||||
textField.alignment = .center
|
||||
textField.font = NSFont.systemFont(
|
||||
ofSize: NSFontDescriptor.preferredFontDescriptor(
|
||||
forTextStyle: .body).pointSize, weight: .bold)
|
||||
textField.font = NSFont.systemFont(ofSize: NSFontDescriptor.preferredFontDescriptor(forTextStyle: .body).pointSize, weight: .bold)
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
return textField
|
||||
}()
|
||||
@@ -104,11 +112,8 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
}()
|
||||
|
||||
private var pathsLabel: NSTextField = {
|
||||
let textField =
|
||||
NSTextField(labelWithString: "Application Directories")
|
||||
textField.font = NSFont.systemFont(
|
||||
ofSize: NSFontDescriptor.preferredFontDescriptor(
|
||||
forTextStyle: .title2).pointSize, weight: .bold)
|
||||
let textField = NSTextField(labelWithString: "Application Directories")
|
||||
textField.font = NSFont.systemFont(ofSize: NSFontDescriptor.preferredFontDescriptor(forTextStyle: .title2).pointSize, weight: .bold)
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
return textField
|
||||
}()
|
||||
@@ -132,8 +137,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
table.allowsColumnReordering = false
|
||||
table.allowsColumnResizing = false
|
||||
table.allowsColumnSelection = false
|
||||
table.addTableColumn(NSTableColumn(
|
||||
identifier: NSUserInterfaceItemIdentifier("Paths")))
|
||||
table.addTableColumn(NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Paths")))
|
||||
|
||||
//rowHeight cgfloat must see doc
|
||||
|
||||
@@ -146,12 +150,8 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
control.segmentCount = 2
|
||||
control.segmentStyle = .roundRect
|
||||
|
||||
control.setImage(
|
||||
NSImage(systemSymbolName: "plus",
|
||||
accessibilityDescription: nil), forSegment: 0)
|
||||
control.setImage(
|
||||
NSImage(systemSymbolName: "minus",
|
||||
accessibilityDescription: nil), forSegment: 1)
|
||||
control.setImage(NSImage(systemSymbolName: "plus", accessibilityDescription: nil), forSegment: 0)
|
||||
control.setImage(NSImage(systemSymbolName: "minus", accessibilityDescription: nil), forSegment: 1)
|
||||
|
||||
control.setToolTip("Add Path", forSegment: 0)
|
||||
control.setToolTip("Remove Path", forSegment: 1)
|
||||
@@ -187,6 +187,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
|
||||
private func addSubviews() {
|
||||
view.addSubview(shortcutsLabel)
|
||||
view.addSubview(aboutButton)
|
||||
view.addSubview(ctrlButton)
|
||||
view.addSubview(cmdButton)
|
||||
view.addSubview(optButton)
|
||||
@@ -204,87 +205,49 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
|
||||
private func setConstraints() {
|
||||
NSLayoutConstraint.activate([
|
||||
shortcutsLabel.topAnchor.constraint(
|
||||
equalTo: view.topAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
shortcutsLabel.leadingAnchor.constraint(
|
||||
equalTo: view.leadingAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
shortcutsLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: ViewConstants.spacing10),
|
||||
shortcutsLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: ViewConstants.spacing10),
|
||||
|
||||
ctrlButton.topAnchor.constraint(
|
||||
equalTo: shortcutsLabel.bottomAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
ctrlButton.leadingAnchor.constraint(
|
||||
equalTo: shortcutsLabel.leadingAnchor),
|
||||
aboutButton.firstBaselineAnchor.constraint(equalTo: shortcutsLabel.firstBaselineAnchor),
|
||||
aboutButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -ViewConstants.spacing10),
|
||||
|
||||
cmdButton.centerYAnchor.constraint(
|
||||
equalTo: ctrlButton.centerYAnchor),
|
||||
cmdButton.leadingAnchor.constraint(
|
||||
equalTo: ctrlButton.trailingAnchor,
|
||||
constant: ViewConstants.spacing5),
|
||||
ctrlButton.topAnchor.constraint(equalTo: shortcutsLabel.bottomAnchor, constant: ViewConstants.spacing10),
|
||||
ctrlButton.leadingAnchor.constraint(equalTo: shortcutsLabel.leadingAnchor),
|
||||
|
||||
optButton.centerYAnchor.constraint(
|
||||
equalTo: ctrlButton.centerYAnchor),
|
||||
optButton.leadingAnchor.constraint(
|
||||
equalTo: cmdButton.trailingAnchor,
|
||||
constant: ViewConstants.spacing5),
|
||||
cmdButton.centerYAnchor.constraint(equalTo: ctrlButton.centerYAnchor),
|
||||
cmdButton.leadingAnchor.constraint(equalTo: ctrlButton.trailingAnchor, constant: ViewConstants.spacing5),
|
||||
|
||||
shiftButton.centerYAnchor.constraint(
|
||||
equalTo: ctrlButton.centerYAnchor),
|
||||
shiftButton.leadingAnchor.constraint(
|
||||
equalTo: optButton.trailingAnchor,
|
||||
constant: ViewConstants.spacing5),
|
||||
optButton.centerYAnchor.constraint(equalTo: ctrlButton.centerYAnchor),
|
||||
optButton.leadingAnchor.constraint(equalTo: cmdButton.trailingAnchor, constant: ViewConstants.spacing5),
|
||||
|
||||
plusLabel.centerYAnchor.constraint(
|
||||
equalTo: ctrlButton.centerYAnchor),
|
||||
plusLabel.leadingAnchor.constraint(
|
||||
equalTo: shiftButton.trailingAnchor,
|
||||
constant: ViewConstants.spacing5),
|
||||
shiftButton.centerYAnchor.constraint(equalTo: ctrlButton.centerYAnchor),
|
||||
shiftButton.leadingAnchor.constraint(equalTo: optButton.trailingAnchor, constant: ViewConstants.spacing5),
|
||||
|
||||
plusLabel.centerYAnchor.constraint(equalTo: ctrlButton.centerYAnchor),
|
||||
plusLabel.leadingAnchor.constraint(equalTo: shiftButton.trailingAnchor, constant: ViewConstants.spacing5),
|
||||
|
||||
recordButton.widthAnchor.constraint(equalToConstant: 40),
|
||||
recordButton.centerYAnchor.constraint(
|
||||
equalTo: ctrlButton.centerYAnchor),
|
||||
recordButton.leadingAnchor.constraint(
|
||||
equalTo: plusLabel.trailingAnchor,
|
||||
constant: ViewConstants.spacing5),
|
||||
recordButton.centerYAnchor.constraint(equalTo: ctrlButton.centerYAnchor),
|
||||
recordButton.leadingAnchor.constraint(equalTo: plusLabel.trailingAnchor, constant: ViewConstants.spacing5),
|
||||
|
||||
pathsLabel.topAnchor.constraint(
|
||||
equalTo: ctrlButton.bottomAnchor,
|
||||
constant: ViewConstants.spacing20),
|
||||
pathsLabel.leadingAnchor.constraint(
|
||||
equalTo: shortcutsLabel.leadingAnchor),
|
||||
pathsLabel.topAnchor.constraint(equalTo: ctrlButton.bottomAnchor, constant: ViewConstants.spacing20),
|
||||
pathsLabel.leadingAnchor.constraint(equalTo: shortcutsLabel.leadingAnchor),
|
||||
|
||||
tableScrollView.widthAnchor.constraint(equalToConstant: 350),
|
||||
tableScrollView.heightAnchor.constraint(equalToConstant: 150),
|
||||
tableScrollView.topAnchor.constraint(
|
||||
equalTo: pathsLabel.bottomAnchor),
|
||||
tableScrollView.leadingAnchor.constraint(
|
||||
equalTo: view.leadingAnchor),
|
||||
tableScrollView.trailingAnchor.constraint(
|
||||
equalTo: view.trailingAnchor),
|
||||
tableScrollView.topAnchor.constraint(equalTo: pathsLabel.bottomAnchor),
|
||||
tableScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tableScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
|
||||
pathsControl.topAnchor.constraint(
|
||||
equalTo: tableScrollView.bottomAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
pathsControl.leadingAnchor.constraint(
|
||||
equalTo: view.leadingAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
pathsControl.topAnchor.constraint(equalTo: tableScrollView.bottomAnchor, constant: ViewConstants.spacing10),
|
||||
pathsControl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: ViewConstants.spacing10),
|
||||
|
||||
launchAtLoginButton.topAnchor.constraint(
|
||||
equalTo: pathsControl.bottomAnchor,
|
||||
constant: ViewConstants.spacing10),
|
||||
launchAtLoginButton.trailingAnchor.constraint(
|
||||
equalTo: resetAllButton.leadingAnchor,
|
||||
constant: -ViewConstants.spacing10),
|
||||
launchAtLoginButton.topAnchor.constraint(equalTo: pathsControl.bottomAnchor, constant: ViewConstants.spacing10),
|
||||
launchAtLoginButton.trailingAnchor.constraint(equalTo: resetAllButton.leadingAnchor, constant: -ViewConstants.spacing10),
|
||||
|
||||
resetAllButton.centerYAnchor.constraint(
|
||||
equalTo: launchAtLoginButton.centerYAnchor),
|
||||
resetAllButton.trailingAnchor.constraint(
|
||||
equalTo: view.trailingAnchor,
|
||||
constant: -ViewConstants.spacing10),
|
||||
resetAllButton.bottomAnchor.constraint(
|
||||
equalTo: view.bottomAnchor,
|
||||
constant: -ViewConstants.spacing10),
|
||||
resetAllButton.centerYAnchor.constraint(equalTo: launchAtLoginButton.centerYAnchor),
|
||||
resetAllButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -ViewConstants.spacing10),
|
||||
resetAllButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -ViewConstants.spacing10),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -320,26 +283,20 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
|
||||
// PERF: Maybe we shouldn't fetch it on every appearance?
|
||||
// Only do it in AppDelegate?
|
||||
if let code =
|
||||
UserDefaults.standard.object(forKey: "keyCode") as? Int
|
||||
{
|
||||
if let code = UserDefaults.standard.object(forKey: "keyCode") as? Int {
|
||||
keyCode = code
|
||||
}
|
||||
if let mods =
|
||||
UserDefaults.standard.object(forKey: "keyModifiers") as? Int
|
||||
{
|
||||
if let mods = UserDefaults.standard.object(forKey: "keyModifiers") as? Int {
|
||||
modifiers = mods
|
||||
}
|
||||
|
||||
pathsTableView.reloadData()
|
||||
loadPaths()
|
||||
syncModifierButtons()
|
||||
launchAtLoginStatus()
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
|
||||
self.view.window?.center()
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
@@ -351,19 +308,34 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
UserDefaults.standard.set(keyCode, forKey: "keyCode")
|
||||
UserDefaults.standard.set(modifiers, forKey: "keyModifiers")
|
||||
|
||||
PathManager.shared.removeEmpty()
|
||||
// Merge PathManagers paths and user paths.
|
||||
// WARNING: This seems a bit error prone.
|
||||
for path in paths {
|
||||
if !PathManager.shared.contains(path) {
|
||||
PathManager.shared.addPath(path)
|
||||
}
|
||||
}
|
||||
for path in PathManager.shared.paths {
|
||||
if !paths.contains(path.key) {
|
||||
PathManager.shared.removePath(path.key)
|
||||
}
|
||||
}
|
||||
PathManager.shared.updateIndex()
|
||||
PathManager.shared.savePaths()
|
||||
PathManager.shared.rebuildIndex()
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
self.view = NSView()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func showAbout() {
|
||||
delegate.showAboutWindow()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func handleModifiers() {
|
||||
// NOTE: Revert to default modifier if none of the modifier
|
||||
// buttons are on.
|
||||
// Revert to default modifier if none of the modifier buttons are on.
|
||||
if cmdButton.state != .on, optButton.state != .on,
|
||||
ctrlButton.state != .on, shiftButton.state != .on
|
||||
{
|
||||
@@ -391,14 +363,23 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
|
||||
@objc
|
||||
private func reset() {
|
||||
keyCode = Int(kVK_Space)
|
||||
keyCode = Int(kVK_Space)
|
||||
modifiers = Int(optionKey)
|
||||
HotKeyManager.shared.registerHotKey(key: keyCode, modifiers: modifiers)
|
||||
UserDefaults.standard.set(keyCode, forKey: "keyCode")
|
||||
UserDefaults.standard.set(modifiers, forKey: "keyModifiers")
|
||||
syncModifierButtons()
|
||||
|
||||
PathManager.shared.reset()
|
||||
PathManager.shared.resetPaths()
|
||||
loadPaths()
|
||||
}
|
||||
|
||||
private func loadPaths() {
|
||||
paths = []
|
||||
for path in PathManager.shared.paths {
|
||||
paths.append(path.key)
|
||||
}
|
||||
paths.sort()
|
||||
pathsTableView.reloadData()
|
||||
}
|
||||
|
||||
@@ -454,25 +435,17 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
let selectedSegment = sender.selectedSegment
|
||||
switch selectedSegment {
|
||||
case 0:
|
||||
// NOTE: Seems a bit error prone.
|
||||
var row = PathManager.shared.userPaths.count-1
|
||||
if !PathManager.shared.userPaths[row].isEmpty {
|
||||
row += 1
|
||||
PathManager.shared.addPath("")
|
||||
pathsTableView.insertRows(at: IndexSet(integer: row),
|
||||
withAnimation: [])
|
||||
}
|
||||
let row = paths.count
|
||||
paths.append("")
|
||||
pathsTableView.insertRows(at: IndexSet(integer: row), withAnimation: [])
|
||||
|
||||
pathsTableView.scrollRowToVisible(row)
|
||||
pathsTableView.selectRowIndexes(IndexSet(integer: row),
|
||||
byExtendingSelection: false)
|
||||
(pathsTableView.view(atColumn: 0, row: row,
|
||||
makeIfNecessary: false) as? PathsTableCellView)?
|
||||
.startEditing()
|
||||
pathsTableView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
|
||||
(pathsTableView.view(atColumn: 0, row: row, makeIfNecessary: false) as? PathsTableCellView)?.startEditing()
|
||||
break
|
||||
case 1:
|
||||
if pathsTableView.selectedRow > -1 {
|
||||
PathManager.shared.userPaths
|
||||
.remove(at: pathsTableView.selectedRow)
|
||||
paths.remove(at: pathsTableView.selectedRow)
|
||||
pathsTableView.reloadData()
|
||||
}
|
||||
break
|
||||
@@ -484,23 +457,18 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
@objc
|
||||
private func editItem(_ sender: NSTableView) {
|
||||
pathsTableView.deselectAll(nil)
|
||||
pathsTableView.selectRowIndexes(
|
||||
IndexSet(integer: pathsTableView.clickedRow),
|
||||
byExtendingSelection: false)
|
||||
pathsTableView.selectRowIndexes(IndexSet(integer: pathsTableView.clickedRow), byExtendingSelection: false)
|
||||
|
||||
if let cell = pathsTableView.view(atColumn: 0,
|
||||
row: pathsTableView.clickedRow,
|
||||
makeIfNecessary: false) as? PathsTableCellView
|
||||
{
|
||||
if let cell = pathsTableView.view(atColumn: 0, row: pathsTableView.clickedRow, makeIfNecessary: false) as? PathsTableCellView {
|
||||
cell.startEditing()
|
||||
}
|
||||
}
|
||||
|
||||
func titleFieldFinishedEditing(tag: Int, text: String) {
|
||||
if text.isEmpty {
|
||||
PathManager.shared.userPaths.remove(at: tag)
|
||||
paths.remove(at: tag)
|
||||
} else {
|
||||
PathManager.shared.userPaths[tag] = text
|
||||
paths[tag] = text
|
||||
}
|
||||
pathsTableView.reloadData()
|
||||
}
|
||||
@@ -515,34 +483,32 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate,
|
||||
func selectionButtonClicked(tag: Int) {
|
||||
NSRunningApplication.current.activate(options: .activateAllWindows)
|
||||
delegate.window.level = .normal
|
||||
delegate.aboutWindow.performClose(nil)
|
||||
|
||||
if dirPicker.runModal() == .OK {
|
||||
if let url = dirPicker.url {
|
||||
PathManager.shared.userPaths[tag] = url.path
|
||||
paths[tag] = url.path
|
||||
pathsTableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
delegate.window.level = .statusBar
|
||||
delegate.window.makeKeyAndOrderFront(nil)
|
||||
if let controller =
|
||||
delegate.window.contentViewController as? SearchViewController
|
||||
{
|
||||
if let controller = delegate.window.contentViewController as? SearchViewController {
|
||||
controller.openSettings()
|
||||
}
|
||||
}
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return PathManager.shared.userPaths.count
|
||||
return paths.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView,
|
||||
viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?
|
||||
{
|
||||
let rect = NSRect(x: 0, y: 0,
|
||||
width: tableColumn!.width, height: 20)
|
||||
let rect = NSRect(x: 0, y: 0, width: tableColumn!.width, height: 20)
|
||||
let cell = PathsTableCellView(frame: rect)
|
||||
cell.titleField.stringValue = PathManager.shared.userPaths[row]
|
||||
cell.titleField.stringValue = paths[row]
|
||||
cell.delegate = self
|
||||
cell.id = row
|
||||
return cell
|
||||
|
||||
Reference in New Issue
Block a user