From e1146840f6548506d00d28726a7ffaec085510cc Mon Sep 17 00:00:00 2001 From: igor Date: Wed, 15 Jan 2025 15:10:11 -0800 Subject: [PATCH] No more keyboard shortcuts sounds in the popover. --- .gitignore | 4 + src/AboutViewController.swift | 8 +- src/AppDelegate.swift | 2 +- src/CBMenuBarItem.swift | 2 +- src/CmdBar.entitlements | 7 +- src/CmdManager.swift | 60 ++++++++------- src/CmdViewController.swift | 96 ++++++++++++------------ src/EditableNSTextField.swift | 54 ++++++++------ src/EventMonitor.swift | 2 +- src/Helpers.swift | 42 +++++++++-- src/LicenseManager.swift | 2 +- src/Makefile | 6 +- src/MenulessWindow.swift | 2 +- src/PopoverPanel.swift | 8 +- src/UpdateViewController.swift | 132 ++++++++++++++++++++------------- src/updater/Makefile | 3 +- 16 files changed, 257 insertions(+), 173 deletions(-) diff --git a/.gitignore b/.gitignore index cd4afb8..4b7b5f5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ arm64 x86_64 build +CmdBar +CmdBar.app +cmdbar_updater +src/updater diff --git a/src/AboutViewController.swift b/src/AboutViewController.swift index 04decfc..30ecb83 100644 --- a/src/AboutViewController.swift +++ b/src/AboutViewController.swift @@ -5,7 +5,7 @@ // Created by Igor Kolokolnikov on 8/16/23. // -import Cocoa +import AppKit // MARK: - Constants fileprivate enum AboutLinks { @@ -24,12 +24,6 @@ enum Strings { static let activating = "Activating..." } -fileprivate enum ViewConstants { - static let spacing2: CGFloat = 2 - static let spacing10: CGFloat = 10 - static let spacing20: CGFloat = 20 -} - // MARK: - Controller class AboutViewController: NSViewController, NSTextFieldDelegate { // MARK: - Views diff --git a/src/AppDelegate.swift b/src/AppDelegate.swift index 0e5284e..498c827 100644 --- a/src/AppDelegate.swift +++ b/src/AppDelegate.swift @@ -1,4 +1,4 @@ -import Cocoa +import AppKit import ServiceManagement class AppDelegate: NSObject, NSApplicationDelegate { diff --git a/src/CBMenuBarItem.swift b/src/CBMenuBarItem.swift index f7c65d4..d64350a 100644 --- a/src/CBMenuBarItem.swift +++ b/src/CBMenuBarItem.swift @@ -28,7 +28,7 @@ // from the coverage of the license being applied to the rest of the code. // -import Cocoa +import AppKit import os final class CBMenuBarItem: NSObject, NSWindowDelegate { diff --git a/src/CmdBar.entitlements b/src/CmdBar.entitlements index 0c67376..4b29477 100644 --- a/src/CmdBar.entitlements +++ b/src/CmdBar.entitlements @@ -1,5 +1,10 @@ - + + com.apple.security.app-sandbox + + com.apple.security.get-task-allow + + diff --git a/src/CmdManager.swift b/src/CmdManager.swift index d0ad443..f362b1f 100644 --- a/src/CmdManager.swift +++ b/src/CmdManager.swift @@ -1,14 +1,12 @@ -import Foundation -import Cocoa +import AppKit -// MARK: - CmdFile class CmdFile { - // MARK: - State private var timer: DispatchSourceTimer? private(set) var lastExec = Int(Date().timeIntervalSince1970) var untilNextExec: Int { get { - let res = reloadTime - (Int(Date().timeIntervalSince1970) - lastExec) + let res = reloadTime - + (Int(Date().timeIntervalSince1970) - lastExec) if res <= 0 { return reloadTime } return res } @@ -16,11 +14,10 @@ class CmdFile { private(set) var url: URL private(set) var reloadTime: Int - private var statusItem: CBMenuBarItem = CBMenuBarItem() + private(set) var statusItem: CBMenuBarItem = CBMenuBarItem() private var shouldWait = false - // MARK: - Initializers init(url: URL, reloadTime: Int) { self.url = url self.reloadTime = reloadTime @@ -37,7 +34,6 @@ class CmdFile { cancelTimer() } - // MARK: - Reload Widget private func reloadWidget() { DispatchQueue.global(qos: .userInitiated).async { [weak self] in if let url = self?.url { @@ -45,10 +41,13 @@ class CmdFile { let execResult = execute(atPath: url) DispatchQueue.main.async { if execResult.title.isEmpty { - self?.statusItem.setImage(title: "exclamationmark.triangle.fill", description: "Warning") + self?.statusItem.setImage( + title: "exclamationmark.triangle.fill", + description: "Warning") self?.statusItem.setTitle("") } else { - self?.statusItem.setImage(title: nil, description: "") + self?.statusItem.setImage(title: nil, + description: "") self?.statusItem.setTitle(execResult.0) } self?.statusItem.setContents(to: execResult.body) @@ -58,7 +57,6 @@ class CmdFile { } } - // MARK: - Timer private func setupTimer() { timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global()) timer?.schedule(deadline: .now(), repeating: .seconds(reloadTime)) @@ -91,15 +89,12 @@ class CmdFile { } } -// MARK: - CmdManager class CmdManager { - //MARK: - State static let standard = CmdManager() var paths: [CmdFile] = [] private var defaultStatusItem: NSStatusItem? - // MARK: - Configure func configure() { getPaths() if paths.isEmpty { @@ -111,23 +106,31 @@ class CmdManager { private func getPaths() { let manager = FileManager.default - let path = manager.homeDirectoryForCurrentUser.appending(path: ".cmdbar") - if let contents = try? manager.contentsOfDirectory(atPath: path.path()) { + let path = manager.homeDirectoryForCurrentUser + .appending(path: ".cmdbar") + if let contents = try? manager + .contentsOfDirectory(atPath: path.path()) { for content in contents { let filePath = path.appending(path: content) let domains = filePath.path().components(separatedBy: ".") if (isValidTimeFormat(domains[domains.count - 1])) { - paths.append(CmdFile(url: filePath, reloadTime: intervalToSeconds(from: domains[domains.count - 1]))) - } else if (domains.last == "sh" && isValidTimeFormat(domains[domains.count - 2])) { - paths.append(CmdFile(url: filePath, reloadTime: intervalToSeconds(from: domains[domains.count - 2]))) + paths.append(CmdFile(url: filePath, + reloadTime: intervalToSeconds( + from: domains[domains.count - 1]))) + } else if domains.last == "sh" && + isValidTimeFormat(domains[domains.count - 2]) { + paths.append(CmdFile(url: filePath, + reloadTime: intervalToSeconds( + from: domains[domains.count - 2]))) } } } } private func setupMenu() { - defaultStatusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + defaultStatusItem = NSStatusBar.system + .statusItem(withLength: NSStatusItem.variableLength) if let btn = defaultStatusItem?.button { let image = NSApp.applicationIconImage image!.size = NSSize(width: 22, height: 22) @@ -135,13 +138,21 @@ class CmdManager { } guard defaultStatusItem != nil else { return } let menu = NSMenu() - menu.addItem(NSMenuItem(title: "Reload", action: #selector(reloadWidgets), keyEquivalent: "")) + menu.addItem(NSMenuItem(title: "Reload", + action: #selector(reloadWidgets), + keyEquivalent: "")) menu.addItem(NSMenuItem.separator()) - menu.addItem(NSMenuItem(title: "About", action: #selector(showAbout), keyEquivalent: "")) + menu.addItem(NSMenuItem(title: "About", + action: #selector(showAbout), + keyEquivalent: "")) menu.addItem(NSMenuItem.separator()) - menu.addItem(NSMenuItem(title: "Check for Updates...", action: #selector(checkForUpdates), keyEquivalent: "")) + menu.addItem(NSMenuItem(title: "Check for Updates...", + action: #selector(checkForUpdates), + keyEquivalent: "")) menu.addItem(NSMenuItem.separator()) - menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) + menu.addItem(NSMenuItem(title: "Quit", + action: #selector(NSApplication.terminate(_:)), + keyEquivalent: "q")) defaultStatusItem!.menu = menu } @@ -164,7 +175,6 @@ class CmdManager { reloadItems() } - // MARK: - NSMenu Functions @objc private func showAbout() { delegate.showAbout() } diff --git a/src/CmdViewController.swift b/src/CmdViewController.swift index d9cc194..322fa26 100644 --- a/src/CmdViewController.swift +++ b/src/CmdViewController.swift @@ -1,22 +1,17 @@ -import Cocoa +import AppKit +import Carbon import ServiceManagement -import OSLog fileprivate enum Metrics { - static let contentMinWidth = 400.0 - static let contentMaxWidth = /*600.0*/ NSScreen.main!.visibleFrame.size.width * 0.7 // REVIEW: Under what circumstances can NSScreen return nil? + static let contentMinWidth = 400.0 + static let contentMaxWidth = /*600.0*/ NSScreen.main!.visibleFrame.size.width * 0.7 // WARNING: Under what circumstances can NSScreen return nil? static let contentMinHeight = 160.0 - static let contentMaxHeight = /*800.0*/ NSScreen.main!.visibleFrame.size.height * 0.8 // REVIEW: Under what circumstances can NSScreen return nil? - static let padding = 10.0 - static let buttonSpacing = 2.0 + static let contentMaxHeight = /*800.0*/ NSScreen.main!.visibleFrame.size.height * 0.8 // WARNING: Under what circumstances can NSScreen return nil? + static let padding = 10.0 + static let buttonSpacing = 2.0 } class CmdViewController: NSViewController { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: CmdViewController.self) - ) - private weak var cmdFile: CmdFile? private var timer: DispatchSourceTimer? private var keyboardEvents: EventMonitor? @@ -332,7 +327,10 @@ class CmdViewController: NSViewController { } private func resetReloadButton() { - reloadButton.image = systemImage("arrow.clockwise.circle.fill", .title2, .large, .init(paletteColors: [.white, .systemBlue])) + reloadButton.image = systemImage("arrow.clockwise.circle.fill", + .title2, .large, + .init(paletteColors: [.white, + .systemBlue])) reloadButton.action = #selector(reloadWidget) reloadButton.toolTip = "Reload Current" } @@ -351,51 +349,51 @@ class CmdViewController: NSViewController { } private func setupKeyEvents() { - keyboardEvents = LocalEventMonitor(mask: [.flagsChanged, .keyDown], handler: { [weak self] event in + keyboardEvents = LocalEventMonitor(mask: [.flagsChanged, .keyDown], + handler: + { [weak self] event in let modifiers = event.modifierFlags.rawValue - let command = NSEvent.ModifierFlags.command.rawValue - let shift = NSEvent.ModifierFlags.shift.rawValue - let control = NSEvent.ModifierFlags.control.rawValue - let option = NSEvent.ModifierFlags.option.rawValue + let key = event.keyCode - if event.modifierFlags.contains(.shift) { - self?.reloadButton.image = systemImage("arrow.clockwise.circle.fill", .title2, .large, .init(paletteColors: [.white, .systemCyan])) + if modsContains(keys: OSShift, in: modifiers) { + self?.reloadButton.image = + systemImage("arrow.clockwise.circle.fill", .title2, + .large,.init(paletteColors: [.white, + .systemCyan])) self?.reloadButton.action = #selector(self?.reloadWidgets) self?.reloadButton.toolTip = "Reload All" } else { - self?.reloadButton.image = systemImage("arrow.clockwise.circle.fill", .title2, .large, .init(paletteColors: [.white, .systemBlue])) + self?.reloadButton.image = + systemImage("arrow.clockwise.circle.fill", .title2, + .large, .init(paletteColors: [.white, + .systemBlue])) self?.reloadButton.action = #selector(self?.reloadWidget) self?.reloadButton.toolTip = "Reload Current" } - // NOTE: Standalone keys should go last! - if (modifiers & command) == command, - (modifiers & (control | shift | option)) == 0, - event.keyCode == 12 // Q - { - self?.terminateApp() - } else if (modifiers & command) == command, - (modifiers & (control | shift | option)) == 0, - event.keyCode == 13 // W - { - self?.view.superview?.window?.resignKey() - } else if (modifiers & command) == command, - (modifiers & (control | shift | option)) == 0, - event.keyCode == 15 // R - { - self?.reloadWidget() - } else if (modifiers & (command & shift)) == command & shift, - (modifiers & (control | option)) == 0, - event.keyCode == 15 // R - { - self?.reloadWidgets() - } else if (modifiers & command) == command, - (modifiers & (control | shift | option)) == 0, - event.keyCode == 8 // C - { - self?.textLabel.currentEditor()?.copy(nil) - } else if event.keyCode == 12 || event.keyCode == 53 { // Q, ESC - self?.view.superview?.window?.resignKey() + if modsContains(keys: OSCmd, in: modifiers) { + if key == kVK_ANSI_Q { + self?.terminateApp() + } else if key == kVK_ANSI_W { + self?.view.superview?.window?.resignKey() + } else if key == kVK_ANSI_R { + self?.reloadWidget() + } else if key == kVK_ANSI_C { + self?.textLabel.currentEditor()?.copy(nil) + } + } else if modsContains(keys: OSCmd | OSShift, in: modifiers) { + if key == kVK_ANSI_R { + // NOTE: We need to resign the window in order to + // prevent the program from intercepting the + // events, which result in sounds beign made for + // missing performKeyEquivalent. + self?.view.window?.resignKey() + self?.reloadWidgets() + } + } else if modsContainsNone(in: modifiers) { + if key == kVK_ANSI_Q || key == kVK_Escape { + self?.view.superview?.window?.resignKey() + } } return event diff --git a/src/EditableNSTextField.swift b/src/EditableNSTextField.swift index 30cf1ee..a010c70 100644 --- a/src/EditableNSTextField.swift +++ b/src/EditableNSTextField.swift @@ -1,32 +1,44 @@ -import Cocoa +import AppKit +import Carbon final class EditableNSTextField: NSTextField { - private let commandKey = NSEvent.ModifierFlags.command.rawValue - private let commandShiftKey = NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue - override func performKeyEquivalent(with event: NSEvent) -> Bool { + let modifiers = event.modifierFlags.rawValue + let key = event.keyCode + if event.type == NSEvent.EventType.keyDown { - if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandKey { - switch event.charactersIgnoringModifiers! { - case "x": - if NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self) { return true } - case "c": - if NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self) { return true } - case "v": - if NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self) { return true } - case "z": - if NSApp.sendAction(Selector(("undo:")), to: nil, from: self) { return true } - case "a": - if NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self) { return true } - default: - break + if modsContains(keys: OSCmd, in: modifiers) { + if key == kVK_ANSI_X { + if NSApp.sendAction(#selector(NSText.cut(_:)), + to: nil, from: self) + { return true } + } else if key == kVK_ANSI_C { + if NSApp.sendAction(#selector(NSText.copy(_:)), + to: nil, from: self) + { return true } + } else if key == kVK_ANSI_V { + if NSApp.sendAction(#selector(NSText.paste(_:)), + to: nil, from: self) + { return true } + } else if key == kVK_ANSI_Z { + if NSApp.sendAction(Selector(("undo:")), + to: nil, from: self) + { return true } + } else if key == kVK_ANSI_A { + if NSApp.sendAction( + #selector(NSResponder.selectAll(_:)), + to: nil, from: self) + { return true } } - } else if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandShiftKey { - if event.charactersIgnoringModifiers == "Z" { - if NSApp.sendAction(Selector(("redo:")), to: nil, from: self) { return true } + } else if modsContains(keys: OSCmd | OSShift, in: modifiers) { + if key == kVK_ANSI_Z { + if NSApp.sendAction(Selector(("redo:")), + to: nil, from: self) + { return true } } } } + return super.performKeyEquivalent(with: event) } } diff --git a/src/EventMonitor.swift b/src/EventMonitor.swift index 1efd0bc..277dd41 100644 --- a/src/EventMonitor.swift +++ b/src/EventMonitor.swift @@ -1,4 +1,4 @@ -import Cocoa +import AppKit class EventMonitor { fileprivate let mask: NSEvent.EventTypeMask diff --git a/src/Helpers.swift b/src/Helpers.swift index e5d75fb..6821267 100644 --- a/src/Helpers.swift +++ b/src/Helpers.swift @@ -1,6 +1,32 @@ import AppKit +import Carbon + +let OSCtrl = NSEvent.ModifierFlags.control.rawValue +let OSCmd = NSEvent.ModifierFlags.command.rawValue +let OSOpt = NSEvent.ModifierFlags.option.rawValue +let OSShift = NSEvent.ModifierFlags.shift.rawValue +let OSMods = UInt(OSCtrl | OSCmd | OSOpt | OSShift) + +func modsContains(keys: UInt, in modifiers: UInt) -> Bool { + return (modifiers & keys) == keys && ((modifiers ^ keys) & OSMods) == 0 +} + +func modsContainsNone(in modifiers: UInt) -> Bool { + return (modifiers & OSMods) == 0 +} + +enum ViewConstants { + static let spacing2: CGFloat = 2 + static let spacing5: CGFloat = 2 + static let spacing10: CGFloat = 10 + static let spacing15: CGFloat = 15 + static let spacing20: CGFloat = 20 + static let spacing25: CGFloat = 25 + static let spacing30: CGFloat = 30 + static let spacing35: CGFloat = 35 + static let spacing40: CGFloat = 40 +} -// MARK: - Tracking Notifications fileprivate extension Notification.Name { static let beginMenuTracking = Notification.Name("com.apple.HIToolbox.beginMenuTrackingNotification") static let endMenuTracking = Notification.Name("com.apple.HIToolbox.endMenuTrackingNotification") @@ -9,10 +35,10 @@ fileprivate extension Notification.Name { #if(DEBUG) struct EndpointConstants { static var versionURL = "http://localhost:8081/version" - static var appURL = "http://localhost:8081/download" - static var appURLZip = "http://localhost:8081/static/app/CmdBar.zip" - static var changelog = "http://localhost:8081/changelog" - static var validateURL = "http://localhost:8081/validate" + static var appURL = "http://localhost:8081/download" + static var appURLZip = "http://localhost:8081/static/app/CmdBar.zip" + static var changelog = "http://localhost:8081/changelog" + static var validateURL = "http://localhost:8081/validate" } #else struct EndpointConstants { @@ -24,7 +50,6 @@ struct EndpointConstants { } #endif -// enum Resulting { case success case failure @@ -156,7 +181,10 @@ func getColors(_ light: NSColor, _ dark: NSColor, for appearance: NSAppearance) } // ex: systemImage("sunrise.circle.fill", .title2, .large, .init(paletteColors: [.white, .systemOrange])) -func systemImage(_ name: String, _ size: NSFont.TextStyle, _ scale: NSImage.SymbolScale, _ configuration: NSImage.SymbolConfiguration) -> NSImage? { +func systemImage(_ name: String, _ size: NSFont.TextStyle, + _ scale: NSImage.SymbolScale, + _ configuration: NSImage.SymbolConfiguration) -> NSImage? +{ return NSImage(systemSymbolName: name, accessibilityDescription: nil)? .withSymbolConfiguration( NSImage.SymbolConfiguration(textStyle: size, scale: scale) diff --git a/src/LicenseManager.swift b/src/LicenseManager.swift index 92c5b21..40a5669 100644 --- a/src/LicenseManager.swift +++ b/src/LicenseManager.swift @@ -5,7 +5,7 @@ // Created by Igor Kolokolnikov on 8/26/23. // -import Cocoa +import AppKit import CryptoKit fileprivate struct LicenseModel: Codable { diff --git a/src/Makefile b/src/Makefile index 44ccb74..06ba4b1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -86,7 +86,11 @@ $(EXEC).app: $(EXEC) cp resources/AppIcon.icns $@/Contents/Resources/ && \ cp $(EXEC) $@/Contents/MacOS/ && \ cp cmdbar_updater $@/Contents/MacOS/ && \ - codesign -s ${DEVELOPER_ID} -f --timestamp -o runtime $(EXEC).app + $(if $(DEBUG), \ + codesign --entitlements Grapp.entitlements \ + -s ${APPLE_DEVELOPMENT} -f --timestamp -o runtime $(EXEC).app, \ + codesign -s ${APPLE_DEVELOPER_ID_APPLICATION} -f --timestamp \ + -o runtime $(EXEC).app) all: zip cmdbar_updater $(EXEC).app diff --git a/src/MenulessWindow.swift b/src/MenulessWindow.swift index c13e346..e80a510 100644 --- a/src/MenulessWindow.swift +++ b/src/MenulessWindow.swift @@ -1,4 +1,4 @@ -import Cocoa +import AppKit class MenulessWindow: NSWindow { init(viewController: NSViewController) { diff --git a/src/PopoverPanel.swift b/src/PopoverPanel.swift index 60c6e13..dce4705 100644 --- a/src/PopoverPanel.swift +++ b/src/PopoverPanel.swift @@ -1,4 +1,4 @@ -import Cocoa +import AppKit class PopoverPanel: NSPanel { override var canBecomeKey: Bool { true } @@ -6,7 +6,8 @@ class PopoverPanel: NSPanel { init(viewController: NSViewController) { super.init( contentRect: CGRect(x: 0, y: 0, width: 100, height: 100), - styleMask: [.titled, .nonactivatingPanel, .utilityWindow, .fullSizeContentView], + styleMask: [.titled, .nonactivatingPanel, .utilityWindow, + .fullSizeContentView], backing: .buffered, defer: false ) @@ -22,7 +23,8 @@ class PopoverPanel: NSPanel { titlebarAppearsTransparent = true animationBehavior = .none - collectionBehavior = [.moveToActiveSpace, .fullScreenAuxiliary, .transient] + collectionBehavior = [.moveToActiveSpace, .fullScreenAuxiliary, + .transient] isReleasedWhenClosed = false hidesOnDeactivate = false diff --git a/src/UpdateViewController.swift b/src/UpdateViewController.swift index dff3aba..6f1205e 100644 --- a/src/UpdateViewController.swift +++ b/src/UpdateViewController.swift @@ -1,28 +1,14 @@ -// -// UpdateViewController.swift -// CmdBar -// -// Created by Igor Kolokolnikov on 5/23/24. -// - import AppKit -fileprivate enum ViewConstants { - static let spacing2: CGFloat = 2 - static let spacing10: CGFloat = 10 - static let spacing20: CGFloat = 20 - static let spacing40: CGFloat = 40 -} - fileprivate enum UpdateStatus: String { - case check = "Check for updates..." - case latest = "You're up-to-date!" - case checking = "Checking for udpates..." - case available = "A new version is available!" - case downloading = "Downloading update..." - case extracting = "Extracting update..." - case install = "Ready to Install" - case checkFailed = "Failed to Check for Updates" + case check = "Check for updates..." + case latest = "You're up-to-date!" + case checking = "Checking for udpates..." + case available = "A new version is available!" + case downloading = "Downloading update..." + case extracting = "Extracting update..." + case install = "Ready to Install" + case checkFailed = "Failed to Check for Updates" case installFailed = "Failed to Install Update" } @@ -30,9 +16,9 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { private weak var updaterDelegate: UpdateManagerDelegate? private var appIconImage: NSImageView = { - //let image = NSImageView(image: NSApp.applicationIconImage) let image = NSImageView() - image.image = NSWorkspace.shared.icon(forFile: Bundle.main.bundlePath) + image.image = NSWorkspace.shared + .icon(forFile: Bundle.main.bundlePath) image.imageScaling = .scaleAxesIndependently image.translatesAutoresizingMaskIntoConstraints = false return image @@ -45,7 +31,9 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { textField.drawsBackground = false textField.alignment = .left textField.textColor = NSColor(name: nil) { getColors(.black, .white, for: $0) } - 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 }() @@ -59,18 +47,23 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { textField.drawsBackground = false textField.alignment = .left textField.textColor = .gray - 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 }() - private var changelogLabel: NSScrollView = { // TODO: Improve some more. Maybe make it scrollable. + // TODO: Improve some more. Maybe make it scrollable. + private var changelogLabel: NSScrollView = { let scrollableTextView = NSTextView.scrollableTextView() scrollableTextView.isHidden = true (scrollableTextView.documentView as? NSTextView)?.isEditable = false -// (scrollableTextView.documentView as? NSTextView)?.drawsBackground = false (scrollableTextView.documentView as? NSTextView)?.textColor = .gray - (scrollableTextView.documentView as? NSTextView)?.font = NSFont.systemFont(ofSize: NSFontDescriptor.preferredFontDescriptor(forTextStyle: .body).pointSize, weight: .regular) + (scrollableTextView.documentView as? NSTextView)?.font = + NSFont.systemFont(ofSize: NSFontDescriptor + .preferredFontDescriptor(forTextStyle: .body).pointSize, + weight: .regular) scrollableTextView.translatesAutoresizingMaskIntoConstraints = false return scrollableTextView }() @@ -139,26 +132,46 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { NSLayoutConstraint.activate([ appIconImage.widthAnchor.constraint(equalToConstant: 70), - appIconImage.heightAnchor.constraint(equalTo: appIconImage.widthAnchor, multiplier: 1), + appIconImage.heightAnchor + .constraint(equalTo: appIconImage.widthAnchor, + multiplier: 1), + appIconImage.topAnchor.constraint(equalTo: view.topAnchor, + constant: ViewConstants.spacing10), + appIconImage.leadingAnchor + .constraint(equalTo: view.leadingAnchor, + constant: ViewConstants.spacing10), - appIconImage.topAnchor.constraint(equalTo: view.topAnchor, constant: ViewConstants.spacing10), - appIconImage.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: ViewConstants.spacing10), + statusLabel.topAnchor + .constraint(equalTo: appIconImage.topAnchor, + constant: ViewConstants.spacing10), + statusLabel.leadingAnchor + .constraint(equalTo: appIconImage.trailingAnchor, + constant: ViewConstants.spacing10), - statusLabel.topAnchor.constraint(equalTo: appIconImage.topAnchor, constant: ViewConstants.spacing2), - statusLabel.leadingAnchor.constraint(equalTo: appIconImage.trailingAnchor, constant: ViewConstants.spacing10), + subStatusLabel.topAnchor + .constraint(equalTo: statusLabel.bottomAnchor, + constant: ViewConstants.spacing10), + subStatusLabel.leadingAnchor + .constraint(equalTo: statusLabel.leadingAnchor), - subStatusLabel.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: ViewConstants.spacing10), - subStatusLabel.leadingAnchor.constraint(equalTo: statusLabel.leadingAnchor), - - changelogLabel.widthAnchor.constraint(equalTo: stackView.widthAnchor), + changelogLabel.widthAnchor + .constraint(equalTo: stackView.widthAnchor), changelogLabel.heightAnchor.constraint(equalToConstant: 150), - stackView.topAnchor.constraint(equalTo: subStatusLabel.bottomAnchor, constant: ViewConstants.spacing2), - stackView.leadingAnchor.constraint(equalTo: statusLabel.leadingAnchor), - view.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: ViewConstants.spacing20), - view.bottomAnchor.constraint(equalTo: stackView.bottomAnchor, constant: ViewConstants.spacing20), + stackView.topAnchor + .constraint(equalTo: subStatusLabel.bottomAnchor, + constant: ViewConstants.spacing2), + stackView.leadingAnchor + .constraint(equalTo: statusLabel.leadingAnchor), + view.trailingAnchor + .constraint(equalTo: stackView.trailingAnchor, + constant: ViewConstants.spacing20), + view.bottomAnchor + .constraint(equalTo: stackView.bottomAnchor, + constant: ViewConstants.spacing20), - buttonsStackView.heightAnchor.constraint(equalTo: updateButton.heightAnchor), + buttonsStackView.heightAnchor + .constraint(equalTo: updateButton.heightAnchor), ]) } @@ -192,36 +205,44 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { case .check: break case .latest: - self?.statusLabel.stringValue = UpdateStatus.latest.rawValue + self?.statusLabel.stringValue = UpdateStatus.latest + .rawValue break case .checking: - self?.statusLabel.stringValue = UpdateStatus.checking.rawValue + self?.statusLabel.stringValue = UpdateStatus.checking + .rawValue self?.updateButton.keyEquivalent = "" self?.updateButton.isEnabled = false case .available: self?.updateButton.title = "Download" self?.updateButton.keyEquivalent = "" - self?.statusLabel.stringValue = UpdateStatus.available.rawValue + self?.statusLabel.stringValue = UpdateStatus.available + .rawValue self?.updateButton.action = #selector(self!.downloadUpdate) case .downloading: self?.updateButton.isEnabled = false self?.updateButton.title = "Install" self?.progressIndicator.isHidden = false - self?.statusLabel.stringValue = UpdateStatus.downloading.rawValue + self?.statusLabel.stringValue = UpdateStatus.downloading + .rawValue case .extracting: self?.updateButton.isEnabled = false self?.updateButton.title = "Install" self?.progressIndicator.isHidden = false - self?.statusLabel.stringValue = UpdateStatus.extracting.rawValue + self?.statusLabel.stringValue = UpdateStatus.extracting + .rawValue case .install: self?.updateButton.title = "Install" self?.progressIndicator.isHidden = false - self?.statusLabel.stringValue = UpdateStatus.install.rawValue + self?.statusLabel.stringValue = UpdateStatus.install + .rawValue self?.updateButton.action = #selector(self!.installUpdate) case .checkFailed: - self?.statusLabel.stringValue = UpdateStatus.checkFailed.rawValue + self?.statusLabel.stringValue = UpdateStatus.checkFailed + .rawValue case .installFailed: - self?.statusLabel.stringValue = UpdateStatus.installFailed.rawValue + self?.statusLabel.stringValue = UpdateStatus.installFailed + .rawValue self?.updateButton.action = #selector(self!.checkForUpdate) } } @@ -241,8 +262,13 @@ class UpdateViewController: NSViewController, UpdateManagerDelegate { self?.subStatusLabel.isHidden = false self?.changelogLabel.isHidden = false for (i, change) in model.changes.enumerated() { - (self?.changelogLabel.documentView as? NSTextView)?.string += "\u{2022} \(change)" - if i < model.changes.count-1 { (self?.changelogLabel.documentView as? NSTextView)?.string += "\n" } + (self?.changelogLabel.documentView as? + NSTextView)?.string += + "\u{2022} \(change)" + if i < model.changes.count-1 { + (self?.changelogLabel.documentView as? + NSTextView)?.string += "\n" + } } } } diff --git a/src/updater/Makefile b/src/updater/Makefile index db71a7a..804f3bf 100644 --- a/src/updater/Makefile +++ b/src/updater/Makefile @@ -20,7 +20,8 @@ FRAMEWORKS = -framework AppKit $(EXEC): ./arm64/$(EXEC) ./x86_64/$(EXEC) lipo -create -output $(EXEC) $^ && \ - codesign -s ${DEVELOPER_ID} -f --timestamp -o runtime $(EXEC) + codesign -s ${APPLE_DEVELOPER_ID_APPLICATION} -f --timestamp \ + -o runtime $(EXEC) all: $(EXEC)