From 327125608aaf75000642ff0212fd1a90bca65f6a Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 15 Apr 2021 23:16:42 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=8C=20Polish=20preferences=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 12 ++ phpmon/Domain/Core/Base.lproj/Main.storyboard | 83 ++++++--- .../Keybinds/GlobalKeybindPreference.swift | 75 ++++++++ phpmon/Domain/Preferences/PrefsVC.swift | 160 +++++++----------- phpmon/Domain/Preferences/PrefsWC.swift | 16 +- phpmon/Localizable.strings | 15 +- 6 files changed, 232 insertions(+), 129 deletions(-) create mode 100644 phpmon/Domain/Preferences/Keybinds/GlobalKeybindPreference.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index c2c1d6b..039c962 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; }; C41C1B4B22B019FF00E7CF16 /* PhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* PhpInstallation.swift */; }; C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4C22B0215A00E7CF16 /* Actions.swift */; }; + C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */; }; C42295DD2358D02000E263B2 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42295DC2358D02000E263B2 /* Command.swift */; }; C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; }; C42759672627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; }; @@ -101,6 +102,7 @@ C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarImageGenerator.swift; sourceTree = ""; }; C41C1B4A22B019FF00E7CF16 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = ""; }; C41C1B4C22B0215A00E7CF16 /* Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = ""; }; + C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = ""; }; C42295DC2358D02000E263B2 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; C42759662627662800093CAE /* NSMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuExtension.swift; sourceTree = ""; }; @@ -162,6 +164,7 @@ C4998F092617633900B2526E /* PrefsWC.swift */, 5420395826135DC100FB00FA /* PrefsVC.swift */, 5420395E2613607600FB00FA /* Preferences.swift */, + C41CD0272628D8E20065BBED /* Keybinds */, ); path = Preferences; sourceTree = ""; @@ -213,6 +216,14 @@ path = phpmon; sourceTree = ""; }; + C41CD0272628D8E20065BBED /* Keybinds */ = { + isa = PBXGroup; + children = ( + C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */, + ); + path = Keybinds; + sourceTree = ""; + }; C41E181722CB61EB0072CF09 /* Domain */ = { isa = PBXGroup; children = ( @@ -421,6 +432,7 @@ C41C1B4722B009A400E7CF16 /* Shell.swift in Sources */, C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */, C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */, + C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */, C42295DD2358D02000E263B2 /* Command.swift in Sources */, C4811D2422D70A4700B5F6B3 /* App.swift in Sources */, C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */, diff --git a/phpmon/Domain/Core/Base.lproj/Main.storyboard b/phpmon/Domain/Core/Base.lproj/Main.storyboard index 4a40938..4119e5d 100644 --- a/phpmon/Domain/Core/Base.lproj/Main.storyboard +++ b/phpmon/Domain/Core/Base.lproj/Main.storyboard @@ -85,21 +85,24 @@ - + - + - + + + + + + + + + + + + + + + + + + + + - + - + @@ -151,19 +187,24 @@ - - - - - - + + + + + + + + + + + - - + + @@ -173,11 +214,13 @@ + + - + diff --git a/phpmon/Domain/Preferences/Keybinds/GlobalKeybindPreference.swift b/phpmon/Domain/Preferences/Keybinds/GlobalKeybindPreference.swift new file mode 100644 index 0000000..58a5a02 --- /dev/null +++ b/phpmon/Domain/Preferences/Keybinds/GlobalKeybindPreference.swift @@ -0,0 +1,75 @@ +// +// GlobalKeybindPreference.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 15/04/2021. +// Copyright © 2021 Nico Verbruggen. All rights reserved. +// + +import Foundation + +struct GlobalKeybindPreference: Codable, CustomStringConvertible { + + // MARK: - Internal variables + + let function : Bool + let control : Bool + let command : Bool + let shift : Bool + let option : Bool + let capsLock : Bool + let carbonFlags : UInt32 + let characters : String? + let keyCode : UInt32 + + // MARK: - How the keybind is display in Preferences + + var description: String { + var stringBuilder = "" + if self.function { + stringBuilder += "Fn" + } + if self.control { + stringBuilder += "⌃" + } + if self.option { + stringBuilder += "⌥" + } + if self.command { + stringBuilder += "⌘" + } + if self.shift { + stringBuilder += "⇧" + } + if self.capsLock { + stringBuilder += "⇪" + } + if let characters = self.characters { + stringBuilder += characters.uppercased() + } + return "\(stringBuilder)" + } + + // MARK: - Persisting data to UserDefaults (as JSON) + + public func toJson() -> String { + let jsonData = try! JSONEncoder().encode(self) + return String(data: jsonData, encoding: .utf8)! + } + + public static func fromJson(_ string: String?) -> GlobalKeybindPreference? { + if string == nil { + return nil + } + + if let jsonData = string!.data(using: .utf8) { + let decoder = JSONDecoder() + do { + return try decoder.decode(GlobalKeybindPreference.self, from: jsonData) + } catch { + return nil + } + } + return nil + } +} diff --git a/phpmon/Domain/Preferences/PrefsVC.swift b/phpmon/Domain/Preferences/PrefsVC.swift index 2b5e5d9..b0ee948 100644 --- a/phpmon/Domain/Preferences/PrefsVC.swift +++ b/phpmon/Domain/Preferences/PrefsVC.swift @@ -12,6 +12,9 @@ import Carbon class PrefsVC: NSViewController { + @IBOutlet weak var leftLabelDynamicIcon: NSTextField! + @IBOutlet weak var leftLabelGlobalShortcut: NSTextField! + @IBOutlet weak var buttonDynamicIcon: NSButton! @IBOutlet weak var labelDynamicIcon: NSTextField! @IBOutlet weak var buttonClose: NSButton! @@ -20,26 +23,6 @@ class PrefsVC: NSViewController { @IBOutlet weak var buttonClearShortcut: NSButton! @IBOutlet weak var labelShortcut: NSTextField! - // MARK: - Variables - - var listening = false { - didSet { - if listening { - DispatchQueue.main.async { [weak self] in - self?.buttonSetShortcut.highlight(true) - self?.buttonSetShortcut.title = "prefs.shortcut_listening".localized - } - } else { - DispatchQueue.main.async { [weak self] in - self?.buttonSetShortcut.highlight(false) - if (App.shared.shortcutHotkey == nil) { - self?.buttonSetShortcut.title = "prefs.shortcut_set".localized - } - } - } - } - } - // MARK: - Display public static func show(delegate: NSWindowDelegate? = nil) { @@ -62,32 +45,73 @@ class PrefsVC: NSViewController { // MARK: - Lifecycle override func viewWillAppear() { - // Load localization - buttonDynamicIcon.title = "prefs.dynamic_icon_title".localized + loadLocalization() + loadDynamicIconFromPreferences() + loadGlobalKeybindFromPreferences() + } + + override func viewWillDisappear() { + if self.listeningForGlobalHotkey { + listeningForGlobalHotkey = false + } + } + + private func loadLocalization() { + // Dynamic icon + leftLabelDynamicIcon.stringValue = "prefs.dynamic_icon".localized labelDynamicIcon.stringValue = "prefs.dynamic_icon_desc".localized - buttonClose.title = "prefs.close".localized + buttonDynamicIcon.title = "prefs.dynamic_icon_title".localized + + // Global Shortcut + leftLabelGlobalShortcut.stringValue = "prefs.global_shortcut".localized labelShortcut.stringValue = "prefs.shortcut_desc".localized buttonSetShortcut.title = "prefs.shortcut_set".localized buttonClearShortcut.title = "prefs.shortcut_clear".localized - let prefs = Preferences.preferences + // Close button + buttonClose.title = "prefs.close".localized + } + + // MARK: - Dynamic Icon Preference + + func loadDynamicIconFromPreferences() { + let shouldDisplay = Preferences.preferences[.shouldDisplayDynamicIcon] as! Bool == true + self.buttonDynamicIcon.state = shouldDisplay ? .on : .off + } + + // MARK: - Shortcut Preference + // Adapted from: https://dev.to/mitchartemis/creating-a-global-configurable-shortcut-for-macos-apps-in-swift-25e9 + + var listeningForGlobalHotkey = false { + didSet { + if listeningForGlobalHotkey { + DispatchQueue.main.async { [weak self] in + self?.buttonSetShortcut.highlight(true) + self?.buttonSetShortcut.title = "prefs.shortcut_listening".localized + } + } else { + DispatchQueue.main.async { [weak self] in + self?.buttonSetShortcut.highlight(false) + self?.loadGlobalKeybindFromPreferences() + } + } + } + } + + func loadGlobalKeybindFromPreferences() { + let globalKeybind = GlobalKeybindPreference.fromJson(Preferences.preferences[.globalHotkey] as! String?) - // Load dynamic icon - self.buttonDynamicIcon.state = (prefs[.shouldDisplayDynamicIcon] as! Bool == true) ? .on : .off - - // Load global keybind initial state - let globalKeybind = GlobalKeybindPreference.fromJson(prefs[.globalHotkey] as! String?) if (globalKeybind != nil) { updateKeybindButton(globalKeybind!) + } else { + buttonSetShortcut.title = "prefs.shortcut_set".localized } + buttonClearShortcut.isEnabled = globalKeybind != nil } - // MARK: - Shortcut - // Adapted from: https://dev.to/mitchartemis/creating-a-global-configurable-shortcut-for-macos-apps-in-swift-25e9 - func updateGlobalShortcut(_ event : NSEvent) { - self.listening = false + self.listeningForGlobalHotkey = false if let characters = event.charactersIgnoringModifiers { let newGlobalKeybind = GlobalKeybindPreference.init( @@ -118,12 +142,12 @@ class PrefsVC: NSViewController { @IBAction func register(_ sender: Any) { unregister(nil) - listening = true + listeningForGlobalHotkey = true view.window?.makeFirstResponder(nil) } @IBAction func unregister(_ sender: Any?) { - listening = false + listeningForGlobalHotkey = false App.shared.shortcutHotkey = nil buttonSetShortcut.title = "" @@ -159,69 +183,3 @@ class PrefsVC: NSViewController { print("VC deallocated") } } - -struct GlobalKeybindPreference: Codable, CustomStringConvertible { - - // MARK: - Internal variables - - let function : Bool - let control : Bool - let command : Bool - let shift : Bool - let option : Bool - let capsLock : Bool - let carbonFlags : UInt32 - let characters : String? - let keyCode : UInt32 - - // MARK: - How the keybind is display in Preferences - - var description: String { - var stringBuilder = "" - if self.function { - stringBuilder += "Fn" - } - if self.control { - stringBuilder += "⌃" - } - if self.option { - stringBuilder += "⌥" - } - if self.command { - stringBuilder += "⌘" - } - if self.shift { - stringBuilder += "⇧" - } - if self.capsLock { - stringBuilder += "⇪" - } - if let characters = self.characters { - stringBuilder += characters.uppercased() - } - return "\(stringBuilder)" - } - - // MARK: - Persisting data to UserDefaults (as JSON) - - public func toJson() -> String { - let jsonData = try! JSONEncoder().encode(self) - return String(data: jsonData, encoding: .utf8)! - } - - public static func fromJson(_ string: String?) -> GlobalKeybindPreference? { - if string == nil { - return nil - } - - if let jsonData = string!.data(using: .utf8) { - let decoder = JSONDecoder() - do { - return try decoder.decode(GlobalKeybindPreference.self, from: jsonData) - } catch { - return nil - } - } - return nil - } -} diff --git a/phpmon/Domain/Preferences/PrefsWC.swift b/phpmon/Domain/Preferences/PrefsWC.swift index da2d31e..08360a8 100644 --- a/phpmon/Domain/Preferences/PrefsWC.swift +++ b/phpmon/Domain/Preferences/PrefsWC.swift @@ -8,17 +8,27 @@ import Cocoa +struct Keys { + static let Escape = 53 + static let Space = 49 +} + class PrefsWC: NSWindowController { - override func windowDidLoad() { super.windowDidLoad() } override func keyDown(with event: NSEvent) { super.keyDown(with: event) + if let vc = self.contentViewController as? PrefsVC { - if vc.listening { - vc.updateGlobalShortcut(event) + if vc.listeningForGlobalHotkey { + if event.keyCode == Keys.Escape || event.keyCode == Keys.Space { + print("A blacklisted key was pressed, canceling listen") + vc.listeningForGlobalHotkey = false + } else { + vc.updateGlobalShortcut(event) + } } } } diff --git a/phpmon/Localizable.strings b/phpmon/Localizable.strings index 3bb963c..8e8f94e 100644 --- a/phpmon/Localizable.strings +++ b/phpmon/Localizable.strings @@ -46,14 +46,19 @@ // PREFERENCES -"prefs.title" = "PHP Monitor: Preferences"; +"prefs.title" = "PHP Monitor"; "prefs.close" = "Close"; -"prefs.dynamic_icon_title" = "Show a dynamic icon in the menu bar"; -"prefs.dynamic_icon_desc" = "If you uncheck this box, the truck icon will always be visible.\nIf checked, it will display the major version number of the currently linked PHP version."; + +"prefs.global_shortcut" = "Global shortcut:"; +"prefs.dynamic_icon" = "Dynamic icon:"; + +"prefs.dynamic_icon_title" = "Display dynamic icon in menu bar"; +"prefs.dynamic_icon_desc" = "If you uncheck this box, the truck icon will always be visible.\nIf checked, it will display the major version number of the\ncurrently linked PHP version."; + "prefs.shortcut_set" = "Set global shortcut"; -"prefs.shortcut_listening" = ""; +"prefs.shortcut_listening" = ""; "prefs.shortcut_clear" = "Clear"; -"prefs.shortcut_desc" = "If a shortcut combination is set up, you can toggle PHP Monitor\nwherever you are by pressing the key combination you chose."; +"prefs.shortcut_desc" = "If a shortcut combination is set up, you can toggle PHP Monitor\nwherever you are by pressing the key combination you chose.\n(Cancel choosing a shortcut by pressing the spacebar.)"; // NOTIFICATIONS