mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
👌 Polish preferences screen
This commit is contained in:
@ -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 = "<group>"; };
|
||||
C41C1B4A22B019FF00E7CF16 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = "<group>"; };
|
||||
C41C1B4C22B0215A00E7CF16 /* Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; };
|
||||
C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = "<group>"; };
|
||||
C42295DC2358D02000E263B2 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
||||
C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = "<group>"; };
|
||||
C42759662627662800093CAE /* NSMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuExtension.swift; sourceTree = "<group>"; };
|
||||
@ -162,6 +164,7 @@
|
||||
C4998F092617633900B2526E /* PrefsWC.swift */,
|
||||
5420395826135DC100FB00FA /* PrefsVC.swift */,
|
||||
5420395E2613607600FB00FA /* Preferences.swift */,
|
||||
C41CD0272628D8E20065BBED /* Keybinds */,
|
||||
);
|
||||
path = Preferences;
|
||||
sourceTree = "<group>";
|
||||
@ -213,6 +216,14 @@
|
||||
path = phpmon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C41CD0272628D8E20065BBED /* Keybinds */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */,
|
||||
);
|
||||
path = Keybinds;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 */,
|
||||
|
@ -85,21 +85,24 @@
|
||||
<objects>
|
||||
<viewController title="Preferences" storyboardIdentifier="preferences" showSeguePresentationStyle="single" id="AW2-rV-rbS" customClass="PrefsVC" customModule="PHP_Monitor" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" wantsLayer="YES" id="Pf1-A5-3Xz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="462" height="185"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="574" height="189"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="GSr-K5-3yw">
|
||||
<rect key="frame" x="373" y="13" width="76" height="32"/>
|
||||
<rect key="frame" x="485" y="13" width="76" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="CLOSE" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ocw-Rx-gyh">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="pressed:" target="AW2-rV-rbS" id="8dA-y4-voq"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MEf-MN-oXt">
|
||||
<rect key="frame" x="18" y="148" width="424" height="18"/>
|
||||
<rect key="frame" x="148" y="152" width="406" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="DYN_ICON" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="m5s-qp-Iaj">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -109,18 +112,32 @@
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JrH-aa-AzL">
|
||||
<rect key="frame" x="18" y="127" width="426" height="14"/>
|
||||
<rect key="frame" x="148" y="131" width="408" height="14"/>
|
||||
<textFieldCell key="cell" title="DYN_ICON_DESC" id="MHA-Xt-xgF">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="V7b-jv-oCB">
|
||||
<rect key="frame" x="13" y="72" width="164" height="32"/>
|
||||
<rect key="frame" x="143" y="75" width="184" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="150" id="9jD-Bf-T2M"/>
|
||||
<constraint firstAttribute="width" constant="170" id="9jD-Bf-T2M"/>
|
||||
</constraints>
|
||||
<backgroundFilters>
|
||||
<ciFilter name="CIDotScreen">
|
||||
<configuration>
|
||||
<real key="inputAngle" value="0.0"/>
|
||||
<ciVector key="inputCenter">
|
||||
<real value="150"/>
|
||||
<real value="150"/>
|
||||
</ciVector>
|
||||
<null key="inputImage"/>
|
||||
<real key="inputSharpness" value="0.69999999999999996"/>
|
||||
<real key="inputWidth" value="6"/>
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</backgroundFilters>
|
||||
<buttonCell key="cell" type="push" title="SET_SHORTCUT" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="R63-tN-KVQ">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -130,20 +147,39 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YsQ-AZ-Aei">
|
||||
<rect key="frame" x="175" y="72" width="154" height="32"/>
|
||||
<rect key="frame" x="325" y="75" width="138" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="CLEAR_SHORTCUT" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nvE-5d-VOS">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<font key="font" metaFont="system" size="11"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="unregister:" target="AW2-rV-rbS" id="2RI-4w-6Td"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5ZK-BG-o1t">
|
||||
<rect key="frame" x="42" y="85" width="100" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="PREF_GLOSHO:" id="xiD-8H-p5s">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="31d-gd-auR">
|
||||
<rect key="frame" x="18" y="153" width="124" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="120" id="8dt-Pg-wFI"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="PREF_DYN_ICON:" id="E10-ss-Cdz">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1TO-9H-z2d">
|
||||
<rect key="frame" x="18" y="57" width="101" height="14"/>
|
||||
<rect key="frame" x="148" y="60" width="101" height="14"/>
|
||||
<textFieldCell key="cell" title="SHORTCUT_DESC" id="nYP-yi-DBf">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
@ -151,19 +187,24 @@
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="JrH-aa-AzL" secondAttribute="trailing" constant="20" symbolic="YES" id="8iM-Xf-ShU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="GSr-K5-3yw" secondAttribute="trailing" constant="20" symbolic="YES" id="AT9-5F-6g1"/>
|
||||
<constraint firstItem="YsQ-AZ-Aei" firstAttribute="leading" secondItem="V7b-jv-oCB" secondAttribute="trailing" constant="8" symbolic="YES" id="Bk6-4V-GLk"/>
|
||||
<constraint firstItem="YsQ-AZ-Aei" firstAttribute="top" secondItem="V7b-jv-oCB" secondAttribute="top" id="CzF-dC-Jm8"/>
|
||||
<constraint firstItem="V7b-jv-oCB" firstAttribute="leading" secondItem="MEf-MN-oXt" secondAttribute="leading" id="El4-TW-O0d"/>
|
||||
<constraint firstItem="MEf-MN-oXt" firstAttribute="top" secondItem="Pf1-A5-3Xz" secondAttribute="top" constant="20" symbolic="YES" id="FJC-Lx-L8a"/>
|
||||
<constraint firstItem="V7b-jv-oCB" firstAttribute="top" secondItem="JrH-aa-AzL" secondAttribute="bottom" constant="28" id="I62-Jw-hfy"/>
|
||||
<constraint firstItem="MEf-MN-oXt" firstAttribute="leading" secondItem="Pf1-A5-3Xz" secondAttribute="leading" constant="20" symbolic="YES" id="Imd-YJ-Ae7"/>
|
||||
<constraint firstItem="YsQ-AZ-Aei" firstAttribute="leading" secondItem="V7b-jv-oCB" secondAttribute="trailing" constant="12" symbolic="YES" id="Bk6-4V-GLk"/>
|
||||
<constraint firstItem="31d-gd-auR" firstAttribute="top" secondItem="Pf1-A5-3Xz" secondAttribute="top" constant="20" symbolic="YES" id="C3K-NX-BBl"/>
|
||||
<constraint firstItem="YsQ-AZ-Aei" firstAttribute="top" secondItem="V7b-jv-oCB" secondAttribute="top" id="DY5-za-saX"/>
|
||||
<constraint firstItem="MEf-MN-oXt" firstAttribute="leading" secondItem="31d-gd-auR" secondAttribute="trailing" constant="10" id="G5S-JV-re3"/>
|
||||
<constraint firstItem="V7b-jv-oCB" firstAttribute="firstBaseline" secondItem="5ZK-BG-o1t" secondAttribute="firstBaseline" id="H5D-2D-DLH"/>
|
||||
<constraint firstItem="1TO-9H-z2d" firstAttribute="leading" secondItem="V7b-jv-oCB" secondAttribute="leading" id="Imk-o0-2fS"/>
|
||||
<constraint firstItem="JrH-aa-AzL" firstAttribute="leading" secondItem="MEf-MN-oXt" secondAttribute="leading" id="K2H-Af-2qK"/>
|
||||
<constraint firstItem="5ZK-BG-o1t" firstAttribute="top" secondItem="JrH-aa-AzL" secondAttribute="bottom" constant="30" id="NMk-yt-fha"/>
|
||||
<constraint firstItem="JrH-aa-AzL" firstAttribute="top" secondItem="MEf-MN-oXt" secondAttribute="bottom" constant="8" symbolic="YES" id="Vf8-fx-H50"/>
|
||||
<constraint firstItem="MEf-MN-oXt" firstAttribute="firstBaseline" secondItem="31d-gd-auR" secondAttribute="firstBaseline" id="W36-bE-iAT"/>
|
||||
<constraint firstItem="1TO-9H-z2d" firstAttribute="firstBaseline" secondItem="V7b-jv-oCB" secondAttribute="baseline" constant="25" id="bJG-ed-pch"/>
|
||||
<constraint firstItem="V7b-jv-oCB" firstAttribute="leading" secondItem="JrH-aa-AzL" secondAttribute="leading" id="bUY-uH-N7A"/>
|
||||
<constraint firstItem="5ZK-BG-o1t" firstAttribute="trailing" secondItem="31d-gd-auR" secondAttribute="trailing" id="c4g-jO-JUm"/>
|
||||
<constraint firstAttribute="bottom" secondItem="GSr-K5-3yw" secondAttribute="bottom" constant="20" symbolic="YES" id="dAS-yW-vua"/>
|
||||
<constraint firstItem="JrH-aa-AzL" firstAttribute="leading" secondItem="MEf-MN-oXt" secondAttribute="leading" id="dzR-S7-M6U"/>
|
||||
<constraint firstItem="1TO-9H-z2d" firstAttribute="leading" secondItem="V7b-jv-oCB" secondAttribute="leading" id="lzx-14-MwL"/>
|
||||
<constraint firstItem="GSr-K5-3yw" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Pf1-A5-3Xz" secondAttribute="leading" constant="20" symbolic="YES" id="mTE-WD-54L"/>
|
||||
<constraint firstItem="31d-gd-auR" firstAttribute="leading" secondItem="Pf1-A5-3Xz" secondAttribute="leading" constant="20" symbolic="YES" id="o0J-yT-TDX"/>
|
||||
<constraint firstAttribute="trailing" secondItem="MEf-MN-oXt" secondAttribute="trailing" constant="20" symbolic="YES" id="pJg-zj-cBs"/>
|
||||
<constraint firstItem="GSr-K5-3yw" firstAttribute="top" secondItem="1TO-9H-z2d" secondAttribute="bottom" constant="20" id="pMZ-Gx-Jmm"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
@ -173,11 +214,13 @@
|
||||
<outlet property="buttonSetShortcut" destination="V7b-jv-oCB" id="2aS-S4-cKR"/>
|
||||
<outlet property="labelDynamicIcon" destination="JrH-aa-AzL" id="CFc-fF-oPq"/>
|
||||
<outlet property="labelShortcut" destination="1TO-9H-z2d" id="paF-hK-78x"/>
|
||||
<outlet property="leftLabelDynamicIcon" destination="31d-gd-auR" id="ANZ-Zs-4d7"/>
|
||||
<outlet property="leftLabelGlobalShortcut" destination="5ZK-BG-o1t" id="73E-9i-cg8"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="eQC-8B-FkX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="208" y="336"/>
|
||||
<point key="canvasLocation" x="264" y="399.5"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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" = "<press for shortcut>";
|
||||
"prefs.shortcut_listening" = "<listening for keypress>";
|
||||
"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
|
||||
|
||||
|
Reference in New Issue
Block a user