From 51d9c81591af471956a322067b208ea2620788de Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 17:50:29 +0200 Subject: [PATCH 01/38] Remove unneeded status item from menu --- Shortcuts for Pi-hole/AppDelegate.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Shortcuts for Pi-hole/AppDelegate.swift b/Shortcuts for Pi-hole/AppDelegate.swift index 8f93bc3..22e2719 100644 --- a/Shortcuts for Pi-hole/AppDelegate.swift +++ b/Shortcuts for Pi-hole/AppDelegate.swift @@ -12,12 +12,7 @@ import Preferences @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - static let menuItems = [AppDelegate.menuItemStatus, AppKit.NSMenuItem.separator(), AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] - - static let menuItemStatus = NSMenuItem(title: "Status", action: nil, keyEquivalent: "", isEnabled: false) - @objc func menuItemStatusActionHandler(_ sender: Any?) { - - } + static let menuItems = [AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] static let menuItemEnable = NSMenuItem(title: "Enable", action: #selector(AppDelegate.menuItemEnableActionHandler(_:)), keyEquivalent: "E", isEnabled: true) @objc func menuItemEnableActionHandler(_ sender: Any?) { From ac2a5cf64cee4dc93fd9ce9a146160429128d596 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 18:16:53 +0200 Subject: [PATCH 02/38] Perform request on enable/disable menu item actions --- Shortcuts for Pi-hole/AppDelegate.swift | 12 ++++++-- Shortcuts for Pi-hole/PiHoleProxy.swift | 41 +++++++++++++++---------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Shortcuts for Pi-hole/AppDelegate.swift b/Shortcuts for Pi-hole/AppDelegate.swift index 22e2719..a573d97 100644 --- a/Shortcuts for Pi-hole/AppDelegate.swift +++ b/Shortcuts for Pi-hole/AppDelegate.swift @@ -16,12 +16,20 @@ class AppDelegate: NSObject, NSApplicationDelegate { static let menuItemEnable = NSMenuItem(title: "Enable", action: #selector(AppDelegate.menuItemEnableActionHandler(_:)), keyEquivalent: "E", isEnabled: true) @objc func menuItemEnableActionHandler(_ sender: Any?) { - + PiHoleProxy.performActionRequest(PiHoleAction.Enable, onSuccess: { (status) in + print("menuItemEnableActionHandler: STATUS " + status) + }) { (error) in + print("menuItemEnableActionHandler: ERROR " + (error?.localizedDescription)!) + } } static let menuItemDisable = NSMenuItem(title: "Disable", action: #selector(AppDelegate.menuItemDisableActionHandler(_:)), keyEquivalent: "D", isEnabled: true) @objc func menuItemDisableActionHandler(_ sender: Any?) { - + PiHoleProxy.performActionRequest(PiHoleAction.Disable, onSuccess: { (status) in + print("menuItemDisableActionHandler: STATUS " + status) + }) { (error) in + print("menuItemDisableActionHandler: ERROR " + (error?.localizedDescription)!) + } } static let menuItemPreferences = NSMenuItem(title: "Preferences", action: #selector(AppDelegate.menuItemPreferenceActionHandler(_:)), keyEquivalent: "P", isEnabled: true) diff --git a/Shortcuts for Pi-hole/PiHoleProxy.swift b/Shortcuts for Pi-hole/PiHoleProxy.swift index f38f642..1cad976 100644 --- a/Shortcuts for Pi-hole/PiHoleProxy.swift +++ b/Shortcuts for Pi-hole/PiHoleProxy.swift @@ -18,15 +18,28 @@ struct ConnectionStatus { } } +enum PiHoleAction { + case Status + case Enable + case Disable +} + class PiHoleProxy: NSObject { - public static func getBaseUrl() -> URL? { + public static func getBaseUrl(action: PiHoleAction = PiHoleAction.Status) -> URL? { let hostAddress = GeneralPreferences.getHostAddress() let hostPort = GeneralPreferences.getHostPort() let requestProtocol = GeneralPreferences.getRequestProtocol() let apiKey = GeneralPreferences.getApiKey() - let urlString = requestProtocol + "://" + hostAddress! + ":" + hostPort + "/admin/api.php?auth=" + apiKey + var urlString = requestProtocol + "://" + hostAddress! + ":" + hostPort + "/admin/api.php?auth=" + apiKey + + if (action == PiHoleAction.Enable) { + urlString = urlString + "&enable" + } else if (action == PiHoleAction.Disable) { + urlString = urlString + "&disable" + } + return URL(string: urlString) } @@ -70,35 +83,29 @@ class PiHoleProxy: NSObject { return URLSession(configuration: config) } - public static func performPiRequest(_ endpoint: String, onSuccess success: @escaping (_ status: String) -> Void, onFailure failure: @escaping (_ error: Error?, _ endpoint: String) -> Void) { - print("performPiRequest: endpoint=" + endpoint) + public static func performActionRequest(_ action: PiHoleAction, onSuccess success: @escaping (_ status: String) -> Void, onFailure failure: @escaping (_ error: Error?) -> Void) { do { - guard let url = URL(string: endpoint) else { - failure(NSError(domain: "Error invalid endpoint", code: 1, userInfo: nil), endpoint) + guard let url = getBaseUrl(action: action) else { + failure(NSError(domain: "Error invalid endpoint", code: 1, userInfo: nil)) return } let urlRequest = URLRequest(url: url) - - let config = URLSessionConfiguration.default - config.timeoutIntervalForRequest = 5 - config.timeoutIntervalForResource = 5 - - let session = URLSession(configuration: config) + let session = getDefaultURLSession() let task = session.dataTask(with: urlRequest) { (data, response, error) in // Check for any errors guard error == nil else { - failure(NSError(domain: "Error at executing request (timeout)", code: 2, userInfo: nil), endpoint) + failure(NSError(domain: "Error at executing request (timeout)", code: 2)) return } // Make sure we got data guard let responseData = data else { - failure(NSError(domain: "Error at reading response", code: 3, userInfo: nil), endpoint) + failure(NSError(domain: "Error at reading response", code: 3, userInfo: nil)) return } @@ -106,19 +113,19 @@ class PiHoleProxy: NSObject { do { guard let responseObj = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: Any] else { - failure(NSError(domain: "Error converting response to JSON", code: 4, userInfo: nil), endpoint) + failure(NSError(domain: "Error converting response to JSON", code: 4, userInfo: nil)) return } // The response object is a dictionary so we just access the title using the "status" key guard let status = responseObj["status"] as? String else { - failure(NSError(domain: "Error getting status from response", code: 5, userInfo: nil), endpoint) + failure(NSError(domain: "Error getting status from response", code: 5, userInfo: nil)) return } success(status) } catch { - failure(NSError(domain: "Error at converting response into JSON", code: 6, userInfo: nil), endpoint) + failure(NSError(domain: "Error at converting response into JSON", code: 6, userInfo: nil)) return } } From 6f015a7ad143fd2b32dbe1888c219498ea72574a Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 18:38:08 +0200 Subject: [PATCH 03/38] Define view for user-set timeout values --- .../GeneralPreferenceViewController.xib | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib index efc3a51..0dad36c 100644 --- a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib +++ b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib @@ -12,6 +12,7 @@ + @@ -19,16 +20,17 @@ - + - + + @@ -37,7 +39,7 @@ - + @@ -47,7 +49,7 @@ - + @@ -60,7 +62,7 @@ - + @@ -70,7 +72,7 @@ - + @@ -84,7 +86,7 @@ - + @@ -94,7 +96,7 @@ - + @@ -112,7 +114,7 @@ - + @@ -122,7 +124,7 @@ - + @@ -136,11 +138,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + - - - @@ -185,8 +208,13 @@ - - - - - - - - + From 8bd2989f15c8d4dd78d34c80d002da5e8593a127 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 18:39:09 +0200 Subject: [PATCH 04/38] Persist timeout values using UserDefaults and read on initializing the default URLSession --- Shortcuts for Pi-hole/PiHoleProxy.swift | 10 ++++++++-- .../GeneralPreferenceViewController.swift | 8 ++++++++ .../PreferenceWindow/GeneralPreferences.swift | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Shortcuts for Pi-hole/PiHoleProxy.swift b/Shortcuts for Pi-hole/PiHoleProxy.swift index 1cad976..8b730f0 100644 --- a/Shortcuts for Pi-hole/PiHoleProxy.swift +++ b/Shortcuts for Pi-hole/PiHoleProxy.swift @@ -64,6 +64,11 @@ class PiHoleProxy: NSObject { return ConnectionStatus(message: "Invalid API Key", color: NSColor.red) } + // check if timeout is valid + if (!GeneralPreferences.isTimeoutValid()) { + return ConnectionStatus(message: "Invalid Timeout Value", color: NSColor.red) + } + // define url on possible host if (getBaseUrl() == nil) { return ConnectionStatus(message: "Invalid URL", color: NSColor.yellow) @@ -75,10 +80,11 @@ class PiHoleProxy: NSObject { public static func getDefaultURLSession() -> URLSession { let config = URLSessionConfiguration.default + let timeout = GeneralPreferences.getTimeout() // timeout 2s - config.timeoutIntervalForRequest = 5 - config.timeoutIntervalForResource = 5 + config.timeoutIntervalForRequest = timeout + config.timeoutIntervalForResource = timeout return URLSession(configuration: config) } diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift index 65a445e..a294533 100644 --- a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift +++ b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift @@ -19,6 +19,7 @@ final class GeneralPreferenceViewController: NSViewController, Preferenceable { @IBOutlet weak var textFieldHostAddress: NSTextField! @IBOutlet weak var viewCircleConnectionStatus: ColoredStatusView! @IBOutlet weak var textFieldConnectionStatus: NSTextField! + @IBOutlet weak var textFieldTimeout: NSTextField! @IBAction func hostAddressActionHandler(_ sender: NSTextField) { let hostAddress = sender.stringValue @@ -84,6 +85,13 @@ final class GeneralPreferenceViewController: NSViewController, Preferenceable { self.onPreferencesChange() } + @IBAction func timeoutActionHandler(_ sender: NSTextField) { + let timeout = sender.doubleValue + print("timeoutActionHandler", timeout) + GeneralPreferences.saveTimeout(timeout: timeout) + + self.onPreferencesChange() + } func onConnectionStatusChange(status: ConnectionStatus) { self.viewCircleConnectionStatus.updateFillingColor(color: status.color) diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift index 1d6fdb1..73d9cfb 100644 --- a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift +++ b/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift @@ -9,7 +9,7 @@ import Cocoa struct GeneralPreferences { - static let (hostAddressKey, hostPortKey, requestProtocolKey, apiKey) = ("HOST_ADDRESS", "HOST_PORT", "REQUEST_PROTOCOL", "API_KEY") + static let (hostAddressKey, hostPortKey, requestProtocolKey, apiKey, timeoutKey) = ("HOST_ADDRESS", "HOST_PORT", "REQUEST_PROTOCOL", "API_KEY", "REQUEST_TIMEOUT") static let userSessionKey = Bundle.main.bundleIdentifier! struct Model { @@ -17,12 +17,14 @@ struct GeneralPreferences { var hostPort: String? var requestProtocol: String? var apiKey: String? + var timeout: String? init(_ json: [String: String]) { self.hostAddress = json[GeneralPreferences.hostAddressKey] self.hostPort = json[GeneralPreferences.hostPortKey] self.requestProtocol = json[GeneralPreferences.requestProtocolKey] self.apiKey = json[GeneralPreferences.apiKey] + self.timeout = json[GeneralPreferences.timeoutKey] } } @@ -54,6 +56,10 @@ struct GeneralPreferences { return Int(hostPort) != nil } + static func isTimeoutValid() -> Bool { + return getTimeout() > 0 + } + static func getHostAddress() -> String? { return UserDefaults.standard.string(forKey: GeneralPreferences.hostAddressKey) } @@ -80,6 +86,10 @@ struct GeneralPreferences { return UserDefaults.standard.string(forKey: GeneralPreferences.apiKey) ?? "" } + static func getTimeout() -> Double { + return UserDefaults.standard.double(forKey: GeneralPreferences.timeoutKey) + } + static func saveHostAddress(hostAddress: String) { UserDefaults.standard.set(hostAddress, forKey: GeneralPreferences.hostAddressKey) } @@ -96,7 +106,11 @@ struct GeneralPreferences { UserDefaults.standard.set(apiKey, forKey: GeneralPreferences.apiKey) } - static var savePreferences = { (hostAddress: String, hostPort: String, requestProtocol: String, apiKey: String) in UserDefaults.standard.set([GeneralPreferences.hostAddressKey: hostAddress, GeneralPreferences.hostPortKey: hostPort, GeneralPreferences.requestProtocolKey: requestProtocol, GeneralPreferences.apiKey: apiKey], forKey: GeneralPreferences.userSessionKey) + static func saveTimeout(timeout: Double) { + UserDefaults.standard.set(timeout, forKey: GeneralPreferences.timeoutKey) + } + + static var savePreferences = { (hostAddress: String, hostPort: String, requestProtocol: String, apiKey: String, timeout: Int) in UserDefaults.standard.set([GeneralPreferences.hostAddressKey: hostAddress, GeneralPreferences.hostPortKey: hostPort, GeneralPreferences.requestProtocolKey: requestProtocol, GeneralPreferences.apiKey: apiKey, GeneralPreferences.timeoutKey: timeout], forKey: GeneralPreferences.userSessionKey) } static var getPreferences = { _ -> Model in From fbe7cf9cc192013c86d94eccea4fec9dee7a1c15 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 18:48:25 +0200 Subject: [PATCH 05/38] Rename PreferencesWindow group to GeneralPreferences --- Shortcuts for Pi-hole.xcodeproj/project.pbxproj | 6 +++--- .../GeneralPreferenceViewController.swift | 0 .../GeneralPreferenceViewController.xib | 0 .../GeneralPreferences.swift | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename Shortcuts for Pi-hole/{PreferenceWindow => GeneralPreferences}/GeneralPreferenceViewController.swift (100%) rename Shortcuts for Pi-hole/{PreferenceWindow => GeneralPreferences}/GeneralPreferenceViewController.xib (100%) rename Shortcuts for Pi-hole/{PreferenceWindow => GeneralPreferences}/GeneralPreferences.swift (100%) diff --git a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj index eb2beb2..2213352 100644 --- a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj +++ b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj @@ -55,7 +55,7 @@ name = Frameworks; sourceTree = ""; }; - 803305662171425000132604 /* PreferenceWindow */ = { + 803305662171425000132604 /* GeneralPreferences */ = { isa = PBXGroup; children = ( 803305672171427400132604 /* GeneralPreferenceViewController.xib */, @@ -63,7 +63,7 @@ 8033056B217152AE00132604 /* GeneralPreferences.swift */, 8033056F2171796B00132604 /* PiHoleProxy.swift */, ); - path = PreferenceWindow; + path = GeneralPreferences; sourceTree = ""; }; 804E3D4321713D1400BD1DA0 = { @@ -88,7 +88,7 @@ isa = PBXGroup; children = ( 803305712171882E00132604 /* Shortcuts for Pi-hole.entitlements */, - 803305662171425000132604 /* PreferenceWindow */, + 803305662171425000132604 /* GeneralPreferences */, 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */, 804E3D5121713D1500BD1DA0 /* Assets.xcassets */, 804E3D5321713D1500BD1DA0 /* MainMenu.xib */, diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift b/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.swift similarity index 100% rename from Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.swift rename to Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.swift diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib b/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib similarity index 100% rename from Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferenceViewController.xib rename to Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib diff --git a/Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift b/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferences.swift similarity index 100% rename from Shortcuts for Pi-hole/PreferenceWindow/GeneralPreferences.swift rename to Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferences.swift From b1be87e4e117d525adcdb5c388ff8eae37b38240 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 13 Oct 2018 23:44:48 +0200 Subject: [PATCH 06/38] Migrate all views to new main storyboard --- .../project.pbxproj | 30 +- Shortcuts for Pi-hole/AppDelegate.swift | 32 +- .../GeneralPreferences.swift | 0 .../GeneralPreferenceViewController.xib | 237 ------------ .../MainWindow/Main.storyboard | 350 ++++++++++++++++++ .../MainPreferencesViewController.swift} | 17 +- .../MainWindow/MainWindowController.swift | 19 + 7 files changed, 408 insertions(+), 277 deletions(-) rename Shortcuts for Pi-hole/{GeneralPreferences => }/GeneralPreferences.swift (100%) delete mode 100644 Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib create mode 100644 Shortcuts for Pi-hole/MainWindow/Main.storyboard rename Shortcuts for Pi-hole/{GeneralPreferences/GeneralPreferenceViewController.swift => MainWindow/MainPreferencesViewController.swift} (91%) create mode 100644 Shortcuts for Pi-hole/MainWindow/MainWindowController.swift diff --git a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj index 2213352..e803a2a 100644 --- a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj +++ b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj @@ -7,14 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 803305682171427400132604 /* GeneralPreferenceViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 803305672171427400132604 /* GeneralPreferenceViewController.xib */; }; - 8033056A2171429100132604 /* GeneralPreferenceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803305692171429100132604 /* GeneralPreferenceViewController.swift */; }; + 8033056A2171429100132604 /* MainPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803305692171429100132604 /* MainPreferencesViewController.swift */; }; 8033056C217152AE00132604 /* GeneralPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8033056B217152AE00132604 /* GeneralPreferences.swift */; }; 8033056E2171649C00132604 /* ColoredStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8033056D2171649C00132604 /* ColoredStatusView.swift */; }; 803305702171796B00132604 /* PiHoleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8033056F2171796B00132604 /* PiHoleProxy.swift */; }; + 8046492121725E3A0028E457 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8046492021725E3A0028E457 /* Main.storyboard */; }; 804E3D5021713D1400BD1DA0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */; }; 804E3D5221713D1500BD1DA0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5121713D1500BD1DA0 /* Assets.xcassets */; }; 804E3D5521713D1500BD1DA0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5321713D1500BD1DA0 /* MainMenu.xib */; }; + 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */; }; 9FBE1CAC0A0BAF179ACE61FC /* Pods_Shortcuts_for_Pi_hole.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 710A42177EE15A4B24668808 /* Pods_Shortcuts_for_Pi_hole.framework */; }; /* End PBXBuildFile section */ @@ -22,17 +23,18 @@ 639B4EFAD3D1CA453BFE7D8D /* Pods-Shortcuts for Pi-hole.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Shortcuts for Pi-hole.release.xcconfig"; path = "Pods/Target Support Files/Pods-Shortcuts for Pi-hole/Pods-Shortcuts for Pi-hole.release.xcconfig"; sourceTree = ""; }; 710A42177EE15A4B24668808 /* Pods_Shortcuts_for_Pi_hole.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Shortcuts_for_Pi_hole.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74562D576827A7D15A133C16 /* Pods-Shortcuts for Pi-hole.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Shortcuts for Pi-hole.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Shortcuts for Pi-hole/Pods-Shortcuts for Pi-hole.debug.xcconfig"; sourceTree = ""; }; - 803305672171427400132604 /* GeneralPreferenceViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GeneralPreferenceViewController.xib; sourceTree = ""; }; - 803305692171429100132604 /* GeneralPreferenceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPreferenceViewController.swift; sourceTree = ""; }; + 803305692171429100132604 /* MainPreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPreferencesViewController.swift; sourceTree = ""; }; 8033056B217152AE00132604 /* GeneralPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPreferences.swift; sourceTree = ""; }; 8033056D2171649C00132604 /* ColoredStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColoredStatusView.swift; sourceTree = ""; }; 8033056F2171796B00132604 /* PiHoleProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PiHoleProxy.swift; path = "Shortcuts for Pi-hole/PiHoleProxy.swift"; sourceTree = SOURCE_ROOT; }; 803305712171882E00132604 /* Shortcuts for Pi-hole.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Shortcuts for Pi-hole.entitlements"; sourceTree = ""; }; + 8046492021725E3A0028E457 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 804E3D4C21713D1400BD1DA0 /* Shortcuts for Pi-hole.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Shortcuts for Pi-hole.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 804E3D5121713D1500BD1DA0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 804E3D5421713D1500BD1DA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 804E3D5621713D1500BD1DA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -55,15 +57,14 @@ name = Frameworks; sourceTree = ""; }; - 803305662171425000132604 /* GeneralPreferences */ = { + 8046491B2172597A0028E457 /* MainWindow */ = { isa = PBXGroup; children = ( - 803305672171427400132604 /* GeneralPreferenceViewController.xib */, - 803305692171429100132604 /* GeneralPreferenceViewController.swift */, - 8033056B217152AE00132604 /* GeneralPreferences.swift */, - 8033056F2171796B00132604 /* PiHoleProxy.swift */, + 8046492021725E3A0028E457 /* Main.storyboard */, + 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */, + 803305692171429100132604 /* MainPreferencesViewController.swift */, ); - path = GeneralPreferences; + path = MainWindow; sourceTree = ""; }; 804E3D4321713D1400BD1DA0 = { @@ -87,8 +88,10 @@ 804E3D4E21713D1400BD1DA0 /* Shortcuts for Pi-hole */ = { isa = PBXGroup; children = ( + 8033056B217152AE00132604 /* GeneralPreferences.swift */, + 8033056F2171796B00132604 /* PiHoleProxy.swift */, + 8046491B2172597A0028E457 /* MainWindow */, 803305712171882E00132604 /* Shortcuts for Pi-hole.entitlements */, - 803305662171425000132604 /* GeneralPreferences */, 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */, 804E3D5121713D1500BD1DA0 /* Assets.xcassets */, 804E3D5321713D1500BD1DA0 /* MainMenu.xib */, @@ -174,7 +177,7 @@ files = ( 804E3D5221713D1500BD1DA0 /* Assets.xcassets in Resources */, 804E3D5521713D1500BD1DA0 /* MainMenu.xib in Resources */, - 803305682171427400132604 /* GeneralPreferenceViewController.xib in Resources */, + 8046492121725E3A0028E457 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -226,8 +229,9 @@ files = ( 803305702171796B00132604 /* PiHoleProxy.swift in Sources */, 8033056C217152AE00132604 /* GeneralPreferences.swift in Sources */, + 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */, 8033056E2171649C00132604 /* ColoredStatusView.swift in Sources */, - 8033056A2171429100132604 /* GeneralPreferenceViewController.swift in Sources */, + 8033056A2171429100132604 /* MainPreferencesViewController.swift in Sources */, 804E3D5021713D1400BD1DA0 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Shortcuts for Pi-hole/AppDelegate.swift b/Shortcuts for Pi-hole/AppDelegate.swift index a573d97..145d9ff 100644 --- a/Shortcuts for Pi-hole/AppDelegate.swift +++ b/Shortcuts for Pi-hole/AppDelegate.swift @@ -12,7 +12,17 @@ import Preferences @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - static let menuItems = [AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] + static let menuItems = [AppDelegate.menuItemAbout, AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] + + static let menuItemAbout = NSMenuItem(title: "About", action: #selector(AppDelegate.menuItemAboutActionHandler(_:)), keyEquivalent: "A", isEnabled: true) + @objc func menuItemAboutActionHandler(_ sender: Any?) { + + } + + static let menuItemPreferences = NSMenuItem(title: "Preferences...", action: #selector(AppDelegate.menuItemPreferenceActionHandler(_:)), keyEquivalent: "P", isEnabled: true) + @objc func menuItemPreferenceActionHandler(_ sender: Any?) { + mainWindowController.showWindow(self) + } static let menuItemEnable = NSMenuItem(title: "Enable", action: #selector(AppDelegate.menuItemEnableActionHandler(_:)), keyEquivalent: "E", isEnabled: true) @objc func menuItemEnableActionHandler(_ sender: Any?) { @@ -32,25 +42,19 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } - static let menuItemPreferences = NSMenuItem(title: "Preferences", action: #selector(AppDelegate.menuItemPreferenceActionHandler(_:)), keyEquivalent: "P", isEnabled: true) - @objc func menuItemPreferenceActionHandler(_ sender: Any?) { - preferencesWindowController.showWindow() - } - static let menuItemQuit = NSMenuItem(title: "Quit " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q", isEnabled: true) - - @IBOutlet weak var window: NSWindow! let statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) @objc func statusBarItemActionHandler(_ sender: NSStatusBarButton) { } - let preferencesWindowController = PreferencesWindowController(viewControllers: [GeneralPreferenceViewController()]) + let mainWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateInitialController() as! MainWindowController func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application - preferencesWindowController.showWindow() + mainWindowController.showWindow(self) + if let button = statusBarItem.button { button.image = NSImage(named:"StatusBarButtonImage") button.action = #selector(self.statusBarItemActionHandler(_:)) @@ -62,18 +66,14 @@ class AppDelegate: NSObject, NSApplicationDelegate { AppDelegate.menuItems.forEach { menuItem in menu.addItem(menuItem) } statusBarItem.menu = menu } - - func applicationWillFinishLaunching(_ notification: Notification) { - window.orderOut(self) - } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application - preferencesWindowController.close() + mainWindowController.close() } @IBAction func preferencesMenuItemActionHandler(_ sender: Any) { - preferencesWindowController.showWindow() + mainWindowController.showWindow(self) } static func NSMenuItem(title: String, action selector: Selector?, keyEquivalent charCode: String, isEnabled: Bool) -> NSMenuItem { diff --git a/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferences.swift b/Shortcuts for Pi-hole/GeneralPreferences.swift similarity index 100% rename from Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferences.swift rename to Shortcuts for Pi-hole/GeneralPreferences.swift diff --git a/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib b/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib deleted file mode 100644 index 0dad36c..0000000 --- a/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.xib +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NSAllRomanInputSourcesLocaleIdentifier - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard new file mode 100644 index 0000000..268deb8 --- /dev/null +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NSAllRomanInputSourcesLocaleIdentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift similarity index 91% rename from Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.swift rename to Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift index a294533..5688295 100644 --- a/Shortcuts for Pi-hole/GeneralPreferences/GeneralPreferenceViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift @@ -7,18 +7,17 @@ // import Cocoa -import Preferences -final class GeneralPreferenceViewController: NSViewController, Preferenceable { - let toolbarItemTitle: String = "General" - let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)! - +final class MainPreferencesViewController: NSViewController { @IBOutlet weak var secureTextFieldApiKey: NSSecureTextField! @IBOutlet weak var popUpButtonRequestProtocol: NSPopUpButton! + @IBOutlet weak var textFieldHostPort: NSTextField! @IBOutlet weak var textFieldHostAddress: NSTextField! + @IBOutlet weak var viewCircleConnectionStatus: ColoredStatusView! - @IBOutlet weak var textFieldConnectionStatus: NSTextField! + + @IBOutlet weak var labelConnectionStatus: NSTextField! @IBOutlet weak var textFieldTimeout: NSTextField! @IBAction func hostAddressActionHandler(_ sender: NSTextField) { @@ -95,7 +94,7 @@ final class GeneralPreferenceViewController: NSViewController, Preferenceable { func onConnectionStatusChange(status: ConnectionStatus) { self.viewCircleConnectionStatus.updateFillingColor(color: status.color) - self.textFieldConnectionStatus.stringValue = status.message + self.labelConnectionStatus.stringValue = status.message } func onPreferencesChange() { @@ -103,10 +102,6 @@ final class GeneralPreferenceViewController: NSViewController, Preferenceable { self.onConnectionStatusChange(status: connectionStatus) } - override var nibName: NSNib.Name? { - return "GeneralPreferenceViewController" - } - override func viewDidLoad() { super.viewDidLoad() diff --git a/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift b/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift new file mode 100644 index 0000000..7b1a589 --- /dev/null +++ b/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift @@ -0,0 +1,19 @@ +// +// MainWindowController.swift +// Shortcuts for Pi-hole +// +// Created by Lukas Wolfsteiner on 13.10.18. +// Copyright © 2018 Lukas Wolfsteiner. All rights reserved. +// + +import Cocoa + +class MainWindowController: NSWindowController { + + override func windowDidLoad() { + super.windowDidLoad() + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + } + +} From 9ce7ceb3c785bde8bc532557afcb19794f05114f Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Thu, 18 Oct 2018 12:10:46 +0200 Subject: [PATCH 07/38] Link example request url field with view controller and display values --- .../project.pbxproj | 14 +- .../MainWindow/Main.storyboard | 138 +++++++++++++++--- .../MainConnectionViewController.swift | 42 ++++++ .../GeneralPreferences.swift | 0 4 files changed, 176 insertions(+), 18 deletions(-) create mode 100644 Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift rename Shortcuts for Pi-hole/{ => Preferences}/GeneralPreferences.swift (100%) diff --git a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj index e803a2a..b1fc94c 100644 --- a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj +++ b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 804E3D5221713D1500BD1DA0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5121713D1500BD1DA0 /* Assets.xcassets */; }; 804E3D5521713D1500BD1DA0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5321713D1500BD1DA0 /* MainMenu.xib */; }; 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */; }; + 80CA005321729EF800CC9FB6 /* MainConnectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CA005221729EF800CC9FB6 /* MainConnectionViewController.swift */; }; 9FBE1CAC0A0BAF179ACE61FC /* Pods_Shortcuts_for_Pi_hole.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 710A42177EE15A4B24668808 /* Pods_Shortcuts_for_Pi_hole.framework */; }; /* End PBXBuildFile section */ @@ -35,6 +36,7 @@ 804E3D5421713D1500BD1DA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 804E3D5621713D1500BD1DA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; + 80CA005221729EF800CC9FB6 /* MainConnectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainConnectionViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -63,6 +65,7 @@ 8046492021725E3A0028E457 /* Main.storyboard */, 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */, 803305692171429100132604 /* MainPreferencesViewController.swift */, + 80CA005221729EF800CC9FB6 /* MainConnectionViewController.swift */, ); path = MainWindow; sourceTree = ""; @@ -88,7 +91,7 @@ 804E3D4E21713D1400BD1DA0 /* Shortcuts for Pi-hole */ = { isa = PBXGroup; children = ( - 8033056B217152AE00132604 /* GeneralPreferences.swift */, + 8065DB1821788F63001E998D /* Preferences */, 8033056F2171796B00132604 /* PiHoleProxy.swift */, 8046491B2172597A0028E457 /* MainWindow */, 803305712171882E00132604 /* Shortcuts for Pi-hole.entitlements */, @@ -101,6 +104,14 @@ path = "Shortcuts for Pi-hole"; sourceTree = ""; }; + 8065DB1821788F63001E998D /* Preferences */ = { + isa = PBXGroup; + children = ( + 8033056B217152AE00132604 /* GeneralPreferences.swift */, + ); + path = Preferences; + sourceTree = ""; + }; C0924F09F3A6ED1030708736 /* Pods */ = { isa = PBXGroup; children = ( @@ -232,6 +243,7 @@ 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */, 8033056E2171649C00132604 /* ColoredStatusView.swift in Sources */, 8033056A2171429100132604 /* MainPreferencesViewController.swift in Sources */, + 80CA005321729EF800CC9FB6 /* MainConnectionViewController.swift in Sources */, 804E3D5021713D1400BD1DA0 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index 268deb8..fb3d9e0 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -30,7 +30,7 @@ - + @@ -58,11 +58,11 @@ - + - + @@ -70,7 +70,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -320,31 +320,135 @@ - + - + - + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift new file mode 100644 index 0000000..fffea62 --- /dev/null +++ b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift @@ -0,0 +1,42 @@ +// +// MainAboutViewController.swift +// Shortcuts for Pi-hole +// +// Created by Lukas Wolfsteiner on 13.10.18. +// Copyright © 2018 Lukas Wolfsteiner. All rights reserved. +// + +import Cocoa + +class MainConnectionViewController: NSViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do view setup here. + } + + @IBAction func connectionButtonActionHandler(_ sender: Any) { + let configStatus = PiHoleProxy.getConfigStatus() + + // config valid + if configStatus.color == NSColor.green { + // display url + let url = PiHoleProxy.getBaseUrl(action: PiHoleAction.Status) + exampleRequestUrlTextField.stringValue = url!.absoluteString + } else { + // show invalid config alert + let alert = NSAlert() + alert.messageText = "Invalid configuration" + alert.informativeText = "Please check your configuration." + alert.addButton(withTitle: "Ok") + alert.beginSheetModal(for: self.view.window!) { (returnCode: NSApplication.ModalResponse) -> Void in + print ("returnCode: ", returnCode) + } + } + } + + + @IBOutlet weak var exampleRequestUrlTextField: NSTextField! + + @IBOutlet var testConnectionTextView: NSTextView! +} diff --git a/Shortcuts for Pi-hole/GeneralPreferences.swift b/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift similarity index 100% rename from Shortcuts for Pi-hole/GeneralPreferences.swift rename to Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift From 3878a7db7a57e372858d39393a8b5fa0b12cfb09 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Thu, 18 Oct 2018 12:18:44 +0200 Subject: [PATCH 08/38] Show tabs as toolbar and add icons to labels --- Shortcuts for Pi-hole/MainWindow/Main.storyboard | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index fb3d9e0..1f097dd 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -30,10 +30,10 @@ - + - - + + @@ -347,7 +347,7 @@ - + @@ -451,4 +451,8 @@ + + + + From e60f0ac32a2cd1f7a47905a1ea73072162656a88 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 20 Oct 2018 21:37:42 +0200 Subject: [PATCH 09/38] Persist and handle port/timeout values as integers --- .../MainPreferencesViewController.swift | 8 +++---- Shortcuts for Pi-hole/PiHoleProxy.swift | 8 ++++--- .../Preferences/GeneralPreferences.swift | 21 +++++++------------ 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift index 5688295..1a40950 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift @@ -63,7 +63,7 @@ final class MainPreferencesViewController: NSViewController { } @IBAction func hostPortActionHandler(_ sender: NSTextField) { - let hostPort = sender.stringValue + let hostPort = sender.integerValue print("hostPortActionHandler", hostPort) GeneralPreferences.saveHostPort(hostPort: hostPort) @@ -85,7 +85,7 @@ final class MainPreferencesViewController: NSViewController { self.onPreferencesChange() } @IBAction func timeoutActionHandler(_ sender: NSTextField) { - let timeout = sender.doubleValue + let timeout = sender.integerValue print("timeoutActionHandler", timeout) GeneralPreferences.saveTimeout(timeout: timeout) @@ -111,9 +111,7 @@ final class MainPreferencesViewController: NSViewController { } let hostPort = GeneralPreferences.getHostPort() - if !hostPort.isEmpty { - textFieldHostPort.stringValue = hostPort - } + textFieldHostPort.integerValue = hostPort let requestProtocol = GeneralPreferences.getRequestProtocol() popUpButtonRequestProtocol.selectItem(withTitle: requestProtocol) diff --git a/Shortcuts for Pi-hole/PiHoleProxy.swift b/Shortcuts for Pi-hole/PiHoleProxy.swift index 8b730f0..8f5e12c 100644 --- a/Shortcuts for Pi-hole/PiHoleProxy.swift +++ b/Shortcuts for Pi-hole/PiHoleProxy.swift @@ -32,8 +32,10 @@ class PiHoleProxy: NSObject { let requestProtocol = GeneralPreferences.getRequestProtocol() let apiKey = GeneralPreferences.getApiKey() - var urlString = requestProtocol + "://" + hostAddress! + ":" + hostPort + "/admin/api.php?auth=" + apiKey + let base = requestProtocol + "://" + hostAddress! + ":" + String(hostPort) + let path: String = "/admin/api.php?auth=" + apiKey + var urlString = base + path if (action == PiHoleAction.Enable) { urlString = urlString + "&enable" } else if (action == PiHoleAction.Disable) { @@ -83,8 +85,8 @@ class PiHoleProxy: NSObject { let timeout = GeneralPreferences.getTimeout() // timeout 2s - config.timeoutIntervalForRequest = timeout - config.timeoutIntervalForResource = timeout + config.timeoutIntervalForRequest = TimeInterval(timeout) + config.timeoutIntervalForResource = TimeInterval(timeout) return URLSession(configuration: config) } diff --git a/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift b/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift index 73d9cfb..068552f 100644 --- a/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift +++ b/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift @@ -52,8 +52,7 @@ struct GeneralPreferences { } static func isHostPortValid() -> Bool { - let hostPort = getHostPort() - return Int(hostPort) != nil + return getHostPort() > 0 } static func isTimeoutValid() -> Bool { @@ -64,13 +63,9 @@ struct GeneralPreferences { return UserDefaults.standard.string(forKey: GeneralPreferences.hostAddressKey) } - static func getHostPort() -> String { - if let hostPort = UserDefaults.standard.string(forKey: GeneralPreferences.hostPortKey), !hostPort.isEmpty { - // it's not nil nor an empty string - return hostPort - } - - return "80" + static func getHostPort() -> Int { + let hostPort = UserDefaults.standard.integer(forKey: GeneralPreferences.hostPortKey) + return (hostPort == 0) ? 80 : hostPort } static func getRequestProtocol() -> String { @@ -86,15 +81,15 @@ struct GeneralPreferences { return UserDefaults.standard.string(forKey: GeneralPreferences.apiKey) ?? "" } - static func getTimeout() -> Double { - return UserDefaults.standard.double(forKey: GeneralPreferences.timeoutKey) + static func getTimeout() -> Int { + return UserDefaults.standard.integer(forKey: GeneralPreferences.timeoutKey) } static func saveHostAddress(hostAddress: String) { UserDefaults.standard.set(hostAddress, forKey: GeneralPreferences.hostAddressKey) } - static func saveHostPort(hostPort: String) { + static func saveHostPort(hostPort: Int) { UserDefaults.standard.set(hostPort, forKey: GeneralPreferences.hostPortKey) } @@ -106,7 +101,7 @@ struct GeneralPreferences { UserDefaults.standard.set(apiKey, forKey: GeneralPreferences.apiKey) } - static func saveTimeout(timeout: Double) { + static func saveTimeout(timeout: Int) { UserDefaults.standard.set(timeout, forKey: GeneralPreferences.timeoutKey) } From aa05232c3af60c7aaf3e49fcca042a36e5757d58 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 20 Oct 2018 21:38:58 +0200 Subject: [PATCH 10/38] Add NumberFormatters to port and timeout text fields --- Shortcuts for Pi-hole/MainWindow/Main.storyboard | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index 1f097dd..c2f7c6a 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -124,7 +124,9 @@ - + + + @@ -197,7 +199,10 @@ - + + + + From e3ab64aae1dc1102d6b34e7628db5b009fd0f47e Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 20 Oct 2018 22:03:56 +0200 Subject: [PATCH 11/38] Implement bottom status bar to display connection details --- .../MainWindow/Main.storyboard | 59 ++++++++++++++++--- .../MainConnectionViewController.swift | 41 ++++++++++++- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index c2f7c6a..e463d13 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -333,11 +333,11 @@ - + - + @@ -345,7 +345,7 @@ - + @@ -371,7 +371,7 @@ - + @@ -379,7 +379,7 @@ - + @@ -419,7 +419,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift index fffea62..eb6f6a8 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift @@ -9,21 +9,34 @@ import Cocoa class MainConnectionViewController: NSViewController { + var connectionStatus: ConnectionStatus? override func viewDidLoad() { super.viewDidLoad() + // Do view setup here. + self.displayBuiltUrl() } - @IBAction func connectionButtonActionHandler(_ sender: Any) { - let configStatus = PiHoleProxy.getConfigStatus() + @IBOutlet weak var coloredStatusViewOutlet: ColoredStatusView! + + @IBOutlet weak var statusMessageLabelOutlet: NSTextField! + + func displayBuiltUrl() { + connectionStatus = PiHoleProxy.getConfigStatus() // config valid - if configStatus.color == NSColor.green { + if connectionStatus!.color == NSColor.green { // display url let url = PiHoleProxy.getBaseUrl(action: PiHoleAction.Status) exampleRequestUrlTextField.stringValue = url!.absoluteString + + statusMessageLabelOutlet.stringValue = "Press connect to verify" + coloredStatusViewOutlet.updateFillingColor(color: NSColor.gray) } else { + statusMessageLabelOutlet.stringValue = "Invalid configuration" + coloredStatusViewOutlet.updateFillingColor(color: NSColor.red) + // show invalid config alert let alert = NSAlert() alert.messageText = "Invalid configuration" @@ -35,6 +48,28 @@ class MainConnectionViewController: NSViewController { } } + @IBAction func connectionButtonActionHandler(_ sender: Any) { + self.displayBuiltUrl() + + if connectionStatus!.color == NSColor.green { + statusMessageLabelOutlet.stringValue = "Requesting..." + coloredStatusViewOutlet.updateFillingColor(color: NSColor.yellow) + + PiHoleProxy.performActionRequest(PiHoleAction.Status, onSuccess: { (status) in + DispatchQueue.main.async { + self.testConnectionTextView.string = "Current Pi-hole status: " + status + self.statusMessageLabelOutlet.stringValue = "Connection established" + self.coloredStatusViewOutlet.updateFillingColor(color: NSColor.green) + } + }) { (error) in + DispatchQueue.main.async { + self.testConnectionTextView.string = error.debugDescription + self.statusMessageLabelOutlet.stringValue = "An error occurred" + self.coloredStatusViewOutlet.updateFillingColor(color: NSColor.red) + } + } + } + } @IBOutlet weak var exampleRequestUrlTextField: NSTextField! From 481c147ccca55d62439b1f70ee5a257d77bbe645 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sat, 20 Oct 2018 22:10:30 +0200 Subject: [PATCH 12/38] Minor source code refactor and cleanup --- Shortcuts for Pi-hole/AppDelegate.swift | 28 +++++----- Shortcuts for Pi-hole/ColoredStatusView.swift | 6 +- .../MainConnectionViewController.swift | 22 ++++---- .../MainPreferencesViewController.swift | 52 ++++++++--------- .../MainWindow/MainWindowController.swift | 2 +- Shortcuts for Pi-hole/PiHoleProxy.swift | 56 +++++++++---------- .../Preferences/GeneralPreferences.swift | 44 +++++++-------- 7 files changed, 105 insertions(+), 105 deletions(-) diff --git a/Shortcuts for Pi-hole/AppDelegate.swift b/Shortcuts for Pi-hole/AppDelegate.swift index 145d9ff..65185e0 100644 --- a/Shortcuts for Pi-hole/AppDelegate.swift +++ b/Shortcuts for Pi-hole/AppDelegate.swift @@ -11,19 +11,19 @@ import Preferences @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - + static let menuItems = [AppDelegate.menuItemAbout, AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] - + static let menuItemAbout = NSMenuItem(title: "About", action: #selector(AppDelegate.menuItemAboutActionHandler(_:)), keyEquivalent: "A", isEnabled: true) @objc func menuItemAboutActionHandler(_ sender: Any?) { - + } - + static let menuItemPreferences = NSMenuItem(title: "Preferences...", action: #selector(AppDelegate.menuItemPreferenceActionHandler(_:)), keyEquivalent: "P", isEnabled: true) @objc func menuItemPreferenceActionHandler(_ sender: Any?) { mainWindowController.showWindow(self) } - + static let menuItemEnable = NSMenuItem(title: "Enable", action: #selector(AppDelegate.menuItemEnableActionHandler(_:)), keyEquivalent: "E", isEnabled: true) @objc func menuItemEnableActionHandler(_ sender: Any?) { PiHoleProxy.performActionRequest(PiHoleAction.Enable, onSuccess: { (status) in @@ -32,7 +32,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { print("menuItemEnableActionHandler: ERROR " + (error?.localizedDescription)!) } } - + static let menuItemDisable = NSMenuItem(title: "Disable", action: #selector(AppDelegate.menuItemDisableActionHandler(_:)), keyEquivalent: "D", isEnabled: true) @objc func menuItemDisableActionHandler(_ sender: Any?) { PiHoleProxy.performActionRequest(PiHoleAction.Disable, onSuccess: { (status) in @@ -41,26 +41,26 @@ class AppDelegate: NSObject, NSApplicationDelegate { print("menuItemDisableActionHandler: ERROR " + (error?.localizedDescription)!) } } - + static let menuItemQuit = NSMenuItem(title: "Quit " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q", isEnabled: true) - + let statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) @objc func statusBarItemActionHandler(_ sender: NSStatusBarButton) { - + } - + let mainWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateInitialController() as! MainWindowController func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application mainWindowController.showWindow(self) - + if let button = statusBarItem.button { - button.image = NSImage(named:"StatusBarButtonImage") + button.image = NSImage(named: "StatusBarButtonImage") button.action = #selector(self.statusBarItemActionHandler(_:)) button.target = self } - + let menu = NSMenu() AppDelegate.menuItems.forEach { menuItem in menu.addItem(menuItem) } @@ -75,7 +75,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBAction func preferencesMenuItemActionHandler(_ sender: Any) { mainWindowController.showWindow(self) } - + static func NSMenuItem(title: String, action selector: Selector?, keyEquivalent charCode: String, isEnabled: Bool) -> NSMenuItem { let menuItem = AppKit.NSMenuItem(title: title, action: selector, keyEquivalent: charCode) menuItem.isEnabled = isEnabled diff --git a/Shortcuts for Pi-hole/ColoredStatusView.swift b/Shortcuts for Pi-hole/ColoredStatusView.swift index 9adb078..eafc1d4 100644 --- a/Shortcuts for Pi-hole/ColoredStatusView.swift +++ b/Shortcuts for Pi-hole/ColoredStatusView.swift @@ -10,17 +10,17 @@ import Cocoa class ColoredStatusView: NSView { var fillingColor: NSColor = NSColor.red - + override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - + // Drawing code here. let fillColor = self.fillingColor let path = NSBezierPath(ovalIn: dirtyRect) fillColor.setFill() path.fill() } - + public func updateFillingColor(color: NSColor) { self.fillingColor = color self.display() diff --git a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift index eb6f6a8..1b54403 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift @@ -13,30 +13,30 @@ class MainConnectionViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() - + // Do view setup here. self.displayBuiltUrl() } - + @IBOutlet weak var coloredStatusViewOutlet: ColoredStatusView! - + @IBOutlet weak var statusMessageLabelOutlet: NSTextField! - + func displayBuiltUrl() { connectionStatus = PiHoleProxy.getConfigStatus() - + // config valid if connectionStatus!.color == NSColor.green { // display url let url = PiHoleProxy.getBaseUrl(action: PiHoleAction.Status) exampleRequestUrlTextField.stringValue = url!.absoluteString - + statusMessageLabelOutlet.stringValue = "Press connect to verify" coloredStatusViewOutlet.updateFillingColor(color: NSColor.gray) } else { statusMessageLabelOutlet.stringValue = "Invalid configuration" coloredStatusViewOutlet.updateFillingColor(color: NSColor.red) - + // show invalid config alert let alert = NSAlert() alert.messageText = "Invalid configuration" @@ -47,14 +47,14 @@ class MainConnectionViewController: NSViewController { } } } - + @IBAction func connectionButtonActionHandler(_ sender: Any) { self.displayBuiltUrl() - + if connectionStatus!.color == NSColor.green { statusMessageLabelOutlet.stringValue = "Requesting..." coloredStatusViewOutlet.updateFillingColor(color: NSColor.yellow) - + PiHoleProxy.performActionRequest(PiHoleAction.Status, onSuccess: { (status) in DispatchQueue.main.async { self.testConnectionTextView.string = "Current Pi-hole status: " + status @@ -70,7 +70,7 @@ class MainConnectionViewController: NSViewController { } } } - + @IBOutlet weak var exampleRequestUrlTextField: NSTextField! @IBOutlet var testConnectionTextView: NSTextView! diff --git a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift index 1a40950..dced4e3 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift @@ -11,49 +11,49 @@ import Cocoa final class MainPreferencesViewController: NSViewController { @IBOutlet weak var secureTextFieldApiKey: NSSecureTextField! @IBOutlet weak var popUpButtonRequestProtocol: NSPopUpButton! - + @IBOutlet weak var textFieldHostPort: NSTextField! @IBOutlet weak var textFieldHostAddress: NSTextField! - + @IBOutlet weak var viewCircleConnectionStatus: ColoredStatusView! - + @IBOutlet weak var labelConnectionStatus: NSTextField! @IBOutlet weak var textFieldTimeout: NSTextField! - + @IBAction func hostAddressActionHandler(_ sender: NSTextField) { let hostAddress = sender.stringValue print("hostAddressActionHandler", hostAddress) GeneralPreferences.saveHostAddress(hostAddress: hostAddress) - + self.onPreferencesChange() } - - + + @IBAction func connectButtonActionHandler(_ sender: NSButton) { self.onConnectionStatusChange(status: ConnectionStatus(message: "Requesting...", color: NSColor.gray)) - + guard let url = PiHoleProxy.getBaseUrl() else { onConnectionStatusChange(status: ConnectionStatus(message: "Error constructing endpoint", color: NSColor.red)) return; } - + let task = PiHoleProxy.getDefaultURLSession().dataTask(with: url) { (data, response, error) in print("dataTask on " + url.absoluteString) - + let connectionStatus: ConnectionStatus; if (error != nil) { connectionStatus = ConnectionStatus(message: error!.localizedDescription, color: NSColor.red) } else if let httpResponse = response as? HTTPURLResponse { let statusCode = httpResponse.statusCode print("status code " + String(describing: statusCode) + " on host " + (url.absoluteString)) - + connectionStatus = ConnectionStatus( message: (statusCode == 200) ? "Connection established" : "Host returned invalid response", color: (statusCode == 200) ? NSColor.green : NSColor.red) } else { connectionStatus = ConnectionStatus(message: "Host returned invalid response", color: NSColor.red) } - + DispatchQueue.main.async { print(connectionStatus.message) self.onConnectionStatusChange(status: connectionStatus) @@ -61,66 +61,66 @@ final class MainPreferencesViewController: NSViewController { } task.resume() } - + @IBAction func hostPortActionHandler(_ sender: NSTextField) { let hostPort = sender.integerValue print("hostPortActionHandler", hostPort) GeneralPreferences.saveHostPort(hostPort: hostPort) - + self.onPreferencesChange() } - + @IBAction func requestProtocolActionHandler(_ sender: NSPopUpButton) { let requestProtocol = sender.titleOfSelectedItem! print("requestProtocolActionHandler", requestProtocol) GeneralPreferences.saveRequestProtocol(requestProtocol: requestProtocol) - + self.onPreferencesChange() } @IBAction func apiKeyActionHandler(_ sender: NSSecureTextField) { let apiKey = sender.stringValue print("apiKeyActionHandler", apiKey) GeneralPreferences.saveApiKey(apiKey: apiKey) - + self.onPreferencesChange() } @IBAction func timeoutActionHandler(_ sender: NSTextField) { let timeout = sender.integerValue print("timeoutActionHandler", timeout) GeneralPreferences.saveTimeout(timeout: timeout) - + self.onPreferencesChange() } - + func onConnectionStatusChange(status: ConnectionStatus) { self.viewCircleConnectionStatus.updateFillingColor(color: status.color) self.labelConnectionStatus.stringValue = status.message } - + func onPreferencesChange() { let connectionStatus = PiHoleProxy.getConfigStatus() self.onConnectionStatusChange(status: connectionStatus) } - + override func viewDidLoad() { super.viewDidLoad() - + // restore persisted preferences in view if let hostAddress = GeneralPreferences.getHostAddress(), !hostAddress.isEmpty { textFieldHostAddress.stringValue = hostAddress } - + let hostPort = GeneralPreferences.getHostPort() textFieldHostPort.integerValue = hostPort - + let requestProtocol = GeneralPreferences.getRequestProtocol() popUpButtonRequestProtocol.selectItem(withTitle: requestProtocol) - + let apiKey = GeneralPreferences.getApiKey() if !apiKey.isEmpty { secureTextFieldApiKey.stringValue = apiKey } - + // check status self.onPreferencesChange() } diff --git a/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift b/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift index 7b1a589..c822ddf 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainWindowController.swift @@ -12,7 +12,7 @@ class MainWindowController: NSWindowController { override func windowDidLoad() { super.windowDidLoad() - + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. } diff --git a/Shortcuts for Pi-hole/PiHoleProxy.swift b/Shortcuts for Pi-hole/PiHoleProxy.swift index 8f5e12c..025986c 100644 --- a/Shortcuts for Pi-hole/PiHoleProxy.swift +++ b/Shortcuts for Pi-hole/PiHoleProxy.swift @@ -11,7 +11,7 @@ import Cocoa struct ConnectionStatus { let message: String let color: NSColor - + init(message: String, color: NSColor) { self.message = message self.color = color @@ -25,114 +25,114 @@ enum PiHoleAction { } class PiHoleProxy: NSObject { - + public static func getBaseUrl(action: PiHoleAction = PiHoleAction.Status) -> URL? { let hostAddress = GeneralPreferences.getHostAddress() let hostPort = GeneralPreferences.getHostPort() let requestProtocol = GeneralPreferences.getRequestProtocol() let apiKey = GeneralPreferences.getApiKey() - + let base = requestProtocol + "://" + hostAddress! + ":" + String(hostPort) let path: String = "/admin/api.php?auth=" + apiKey - + var urlString = base + path if (action == PiHoleAction.Enable) { urlString = urlString + "&enable" } else if (action == PiHoleAction.Disable) { urlString = urlString + "&disable" } - + return URL(string: urlString) } - + public static func getConfigStatus() -> ConnectionStatus { // check if host address is valid if (!GeneralPreferences.isHostAddressValid()) { return ConnectionStatus(message: "Invalid Host Address", color: NSColor.red) } - + // check if host port is valid if (!GeneralPreferences.isHostPortValid()) { return ConnectionStatus(message: "Invalid Host Port", color: NSColor.red) } - + // check if request protocol is valid if (!GeneralPreferences.isRequestProtocolValid()) { return ConnectionStatus(message: "Invalid Protocol", color: NSColor.red) } - + // check if api key is valid if (!GeneralPreferences.isApiKeyValid()) { return ConnectionStatus(message: "Invalid API Key", color: NSColor.red) } - + // check if timeout is valid if (!GeneralPreferences.isTimeoutValid()) { return ConnectionStatus(message: "Invalid Timeout Value", color: NSColor.red) } - + // define url on possible host if (getBaseUrl() == nil) { return ConnectionStatus(message: "Invalid URL", color: NSColor.yellow) } - + // config looks good! return ConnectionStatus(message: "Configuration looks valid", color: NSColor.green) } - + public static func getDefaultURLSession() -> URLSession { let config = URLSessionConfiguration.default let timeout = GeneralPreferences.getTimeout() - + // timeout 2s config.timeoutIntervalForRequest = TimeInterval(timeout) config.timeoutIntervalForResource = TimeInterval(timeout) - + return URLSession(configuration: config) } - + public static func performActionRequest(_ action: PiHoleAction, onSuccess success: @escaping (_ status: String) -> Void, onFailure failure: @escaping (_ error: Error?) -> Void) { - + do { guard let url = getBaseUrl(action: action) else { failure(NSError(domain: "Error invalid endpoint", code: 1, userInfo: nil)) return } - + let urlRequest = URLRequest(url: url) let session = getDefaultURLSession() - + let task = session.dataTask(with: urlRequest) { (data, response, error) in - + // Check for any errors guard error == nil else { failure(NSError(domain: "Error at executing request (timeout)", code: 2)) return } - + // Make sure we got data guard let responseData = data else { failure(NSError(domain: "Error at reading response", code: 3, userInfo: nil)) return } - + // Parse the result as JSON, since that's what the API provides do { guard let responseObj = try JSONSerialization.jsonObject(with: responseData, options: []) - as? [String: Any] else { - failure(NSError(domain: "Error converting response to JSON", code: 4, userInfo: nil)) - return + as? [String: Any] else { + failure(NSError(domain: "Error converting response to JSON", code: 4, userInfo: nil)) + return } - + // The response object is a dictionary so we just access the title using the "status" key guard let status = responseObj["status"] as? String else { failure(NSError(domain: "Error getting status from response", code: 5, userInfo: nil)) return } - + success(status) - } catch { + } catch { failure(NSError(domain: "Error at converting response into JSON", code: 6, userInfo: nil)) return } diff --git a/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift b/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift index 068552f..4408bc3 100644 --- a/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift +++ b/Shortcuts for Pi-hole/Preferences/GeneralPreferences.swift @@ -11,14 +11,14 @@ import Cocoa struct GeneralPreferences { static let (hostAddressKey, hostPortKey, requestProtocolKey, apiKey, timeoutKey) = ("HOST_ADDRESS", "HOST_PORT", "REQUEST_PROTOCOL", "API_KEY", "REQUEST_TIMEOUT") static let userSessionKey = Bundle.main.bundleIdentifier! - + struct Model { var hostAddress: String? var hostPort: String? var requestProtocol: String? var apiKey: String? var timeout: String? - + init(_ json: [String: String]) { self.hostAddress = json[GeneralPreferences.hostAddressKey] self.hostPort = json[GeneralPreferences.hostPortKey] @@ -27,7 +27,7 @@ struct GeneralPreferences { self.timeout = json[GeneralPreferences.timeoutKey] } } - + static func isHostAddressValid() -> Bool { if let hostAddress = UserDefaults.standard.string(forKey: GeneralPreferences.hostAddressKey), !hostAddress.isEmpty { // it's not nil nor an empty string @@ -36,12 +36,12 @@ struct GeneralPreferences { return false } } - + static func isRequestProtocolValid() -> Bool { let requestProtocol = getRequestProtocol() return requestProtocol == "http" || requestProtocol == "https" } - + static func isApiKeyValid() -> Bool { if let apiKey = UserDefaults.standard.string(forKey: GeneralPreferences.apiKey), !apiKey.isEmpty { // it's not nil nor an empty string @@ -50,69 +50,69 @@ struct GeneralPreferences { return false } } - + static func isHostPortValid() -> Bool { return getHostPort() > 0 } - + static func isTimeoutValid() -> Bool { return getTimeout() > 0 } - + static func getHostAddress() -> String? { return UserDefaults.standard.string(forKey: GeneralPreferences.hostAddressKey) } - + static func getHostPort() -> Int { let hostPort = UserDefaults.standard.integer(forKey: GeneralPreferences.hostPortKey) return (hostPort == 0) ? 80 : hostPort } - + static func getRequestProtocol() -> String { if let requestProtocol = UserDefaults.standard.string(forKey: GeneralPreferences.requestProtocolKey), !requestProtocol.isEmpty { // it's not nil nor an empty string return requestProtocol } - + return "http" } - + static func getApiKey() -> String { return UserDefaults.standard.string(forKey: GeneralPreferences.apiKey) ?? "" } - + static func getTimeout() -> Int { return UserDefaults.standard.integer(forKey: GeneralPreferences.timeoutKey) } - + static func saveHostAddress(hostAddress: String) { UserDefaults.standard.set(hostAddress, forKey: GeneralPreferences.hostAddressKey) } - + static func saveHostPort(hostPort: Int) { UserDefaults.standard.set(hostPort, forKey: GeneralPreferences.hostPortKey) } - + static func saveRequestProtocol(requestProtocol: String) { UserDefaults.standard.set(requestProtocol, forKey: GeneralPreferences.requestProtocolKey) } - + static func saveApiKey(apiKey: String) { UserDefaults.standard.set(apiKey, forKey: GeneralPreferences.apiKey) } - + static func saveTimeout(timeout: Int) { UserDefaults.standard.set(timeout, forKey: GeneralPreferences.timeoutKey) } - + static var savePreferences = { (hostAddress: String, hostPort: String, requestProtocol: String, apiKey: String, timeout: Int) in UserDefaults.standard.set([GeneralPreferences.hostAddressKey: hostAddress, GeneralPreferences.hostPortKey: hostPort, GeneralPreferences.requestProtocolKey: requestProtocol, GeneralPreferences.apiKey: apiKey, GeneralPreferences.timeoutKey: timeout], forKey: GeneralPreferences.userSessionKey) } - + static var getPreferences = { _ -> Model in return Model((UserDefaults.standard.value(forKey: GeneralPreferences.userSessionKey) as? [String: String]) ?? [:]) }(()) - - static func clearPreferences(){ + + static func clearPreferences() { UserDefaults.standard.removeObject(forKey: GeneralPreferences.userSessionKey) } } From 9a7f6c9babee494131f79f60ff26c0847b16d026 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sun, 21 Oct 2018 01:00:11 +0200 Subject: [PATCH 13/38] Move menu handling into own layout file and controller --- .../project.pbxproj | 31 +- Shortcuts for Pi-hole/AppDelegate.swift | 62 -- Shortcuts for Pi-hole/Base.lproj/MainMenu.xib | 708 ------------------ .../MainPreferencesViewController.swift | 34 - .../StatusBarMenu/MainMenu.xib | 101 +++ .../StatusBarMenu/MainMenuController.swift | 83 ++ 6 files changed, 200 insertions(+), 819 deletions(-) delete mode 100644 Shortcuts for Pi-hole/Base.lproj/MainMenu.xib create mode 100644 Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib create mode 100644 Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift diff --git a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj index b1fc94c..2678fb6 100644 --- a/Shortcuts for Pi-hole.xcodeproj/project.pbxproj +++ b/Shortcuts for Pi-hole.xcodeproj/project.pbxproj @@ -14,9 +14,10 @@ 8046492121725E3A0028E457 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8046492021725E3A0028E457 /* Main.storyboard */; }; 804E3D5021713D1400BD1DA0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */; }; 804E3D5221713D1500BD1DA0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5121713D1500BD1DA0 /* Assets.xcassets */; }; - 804E3D5521713D1500BD1DA0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 804E3D5321713D1500BD1DA0 /* MainMenu.xib */; }; 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */; }; 80CA005321729EF800CC9FB6 /* MainConnectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CA005221729EF800CC9FB6 /* MainConnectionViewController.swift */; }; + 80ECF9AD217BC3E500879DA2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80ECF9AC217BC3E500879DA2 /* MainMenu.xib */; }; + 80ECF9B0217BCE9400879DA2 /* MainMenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80ECF9AF217BCE9400879DA2 /* MainMenuController.swift */; }; 9FBE1CAC0A0BAF179ACE61FC /* Pods_Shortcuts_for_Pi_hole.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 710A42177EE15A4B24668808 /* Pods_Shortcuts_for_Pi_hole.framework */; }; /* End PBXBuildFile section */ @@ -33,10 +34,11 @@ 804E3D4C21713D1400BD1DA0 /* Shortcuts for Pi-hole.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Shortcuts for Pi-hole.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 804E3D5121713D1500BD1DA0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 804E3D5421713D1500BD1DA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 804E3D5621713D1500BD1DA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80CA003F217260DA00CC9FB6 /* MainWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 80CA005221729EF800CC9FB6 /* MainConnectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainConnectionViewController.swift; sourceTree = ""; }; + 80ECF9AC217BC3E500879DA2 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; + 80ECF9AF217BCE9400879DA2 /* MainMenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenuController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -91,13 +93,13 @@ 804E3D4E21713D1400BD1DA0 /* Shortcuts for Pi-hole */ = { isa = PBXGroup; children = ( + 80ECF9AE217BCD6700879DA2 /* StatusBarMenu */, 8065DB1821788F63001E998D /* Preferences */, 8033056F2171796B00132604 /* PiHoleProxy.swift */, 8046491B2172597A0028E457 /* MainWindow */, 803305712171882E00132604 /* Shortcuts for Pi-hole.entitlements */, 804E3D4F21713D1400BD1DA0 /* AppDelegate.swift */, 804E3D5121713D1500BD1DA0 /* Assets.xcassets */, - 804E3D5321713D1500BD1DA0 /* MainMenu.xib */, 804E3D5621713D1500BD1DA0 /* Info.plist */, 8033056D2171649C00132604 /* ColoredStatusView.swift */, ); @@ -112,6 +114,15 @@ path = Preferences; sourceTree = ""; }; + 80ECF9AE217BCD6700879DA2 /* StatusBarMenu */ = { + isa = PBXGroup; + children = ( + 80ECF9AC217BC3E500879DA2 /* MainMenu.xib */, + 80ECF9AF217BCE9400879DA2 /* MainMenuController.swift */, + ); + path = StatusBarMenu; + sourceTree = ""; + }; C0924F09F3A6ED1030708736 /* Pods */ = { isa = PBXGroup; children = ( @@ -186,8 +197,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 80ECF9AD217BC3E500879DA2 /* MainMenu.xib in Resources */, 804E3D5221713D1500BD1DA0 /* Assets.xcassets in Resources */, - 804E3D5521713D1500BD1DA0 /* MainMenu.xib in Resources */, 8046492121725E3A0028E457 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -240,6 +251,7 @@ files = ( 803305702171796B00132604 /* PiHoleProxy.swift in Sources */, 8033056C217152AE00132604 /* GeneralPreferences.swift in Sources */, + 80ECF9B0217BCE9400879DA2 /* MainMenuController.swift in Sources */, 80CA0040217260DA00CC9FB6 /* MainWindowController.swift in Sources */, 8033056E2171649C00132604 /* ColoredStatusView.swift in Sources */, 8033056A2171429100132604 /* MainPreferencesViewController.swift in Sources */, @@ -250,17 +262,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 804E3D5321713D1500BD1DA0 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 804E3D5421713D1500BD1DA0 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 804E3D5821713D1500BD1DA0 /* Debug */ = { isa = XCBuildConfiguration; diff --git a/Shortcuts for Pi-hole/AppDelegate.swift b/Shortcuts for Pi-hole/AppDelegate.swift index 65185e0..d9e5cc2 100644 --- a/Shortcuts for Pi-hole/AppDelegate.swift +++ b/Shortcuts for Pi-hole/AppDelegate.swift @@ -12,74 +12,12 @@ import Preferences @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - static let menuItems = [AppDelegate.menuItemAbout, AppDelegate.menuItemPreferences, AppKit.NSMenuItem.separator(), AppDelegate.menuItemEnable, AppDelegate.menuItemDisable, AppKit.NSMenuItem.separator(), AppDelegate.menuItemQuit] - - static let menuItemAbout = NSMenuItem(title: "About", action: #selector(AppDelegate.menuItemAboutActionHandler(_:)), keyEquivalent: "A", isEnabled: true) - @objc func menuItemAboutActionHandler(_ sender: Any?) { - - } - - static let menuItemPreferences = NSMenuItem(title: "Preferences...", action: #selector(AppDelegate.menuItemPreferenceActionHandler(_:)), keyEquivalent: "P", isEnabled: true) - @objc func menuItemPreferenceActionHandler(_ sender: Any?) { - mainWindowController.showWindow(self) - } - - static let menuItemEnable = NSMenuItem(title: "Enable", action: #selector(AppDelegate.menuItemEnableActionHandler(_:)), keyEquivalent: "E", isEnabled: true) - @objc func menuItemEnableActionHandler(_ sender: Any?) { - PiHoleProxy.performActionRequest(PiHoleAction.Enable, onSuccess: { (status) in - print("menuItemEnableActionHandler: STATUS " + status) - }) { (error) in - print("menuItemEnableActionHandler: ERROR " + (error?.localizedDescription)!) - } - } - - static let menuItemDisable = NSMenuItem(title: "Disable", action: #selector(AppDelegate.menuItemDisableActionHandler(_:)), keyEquivalent: "D", isEnabled: true) - @objc func menuItemDisableActionHandler(_ sender: Any?) { - PiHoleProxy.performActionRequest(PiHoleAction.Disable, onSuccess: { (status) in - print("menuItemDisableActionHandler: STATUS " + status) - }) { (error) in - print("menuItemDisableActionHandler: ERROR " + (error?.localizedDescription)!) - } - } - - static let menuItemQuit = NSMenuItem(title: "Quit " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q", isEnabled: true) - - let statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) - @objc func statusBarItemActionHandler(_ sender: NSStatusBarButton) { - - } - - let mainWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateInitialController() as! MainWindowController - func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application - mainWindowController.showWindow(self) - - if let button = statusBarItem.button { - button.image = NSImage(named: "StatusBarButtonImage") - button.action = #selector(self.statusBarItemActionHandler(_:)) - button.target = self - } - - let menu = NSMenu() - - AppDelegate.menuItems.forEach { menuItem in menu.addItem(menuItem) } - statusBarItem.menu = menu } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application - mainWindowController.close() - } - - @IBAction func preferencesMenuItemActionHandler(_ sender: Any) { - mainWindowController.showWindow(self) - } - - static func NSMenuItem(title: String, action selector: Selector?, keyEquivalent charCode: String, isEnabled: Bool) -> NSMenuItem { - let menuItem = AppKit.NSMenuItem(title: title, action: selector, keyEquivalent: charCode) - menuItem.isEnabled = isEnabled - return menuItem } } diff --git a/Shortcuts for Pi-hole/Base.lproj/MainMenu.xib b/Shortcuts for Pi-hole/Base.lproj/MainMenu.xib deleted file mode 100644 index bcb5399..0000000 --- a/Shortcuts for Pi-hole/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,708 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift index dced4e3..7c57798 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainPreferencesViewController.swift @@ -28,40 +28,6 @@ final class MainPreferencesViewController: NSViewController { self.onPreferencesChange() } - - @IBAction func connectButtonActionHandler(_ sender: NSButton) { - self.onConnectionStatusChange(status: ConnectionStatus(message: "Requesting...", color: NSColor.gray)) - - guard let url = PiHoleProxy.getBaseUrl() else { - onConnectionStatusChange(status: ConnectionStatus(message: "Error constructing endpoint", color: NSColor.red)) - return; - } - - let task = PiHoleProxy.getDefaultURLSession().dataTask(with: url) { (data, response, error) in - print("dataTask on " + url.absoluteString) - - let connectionStatus: ConnectionStatus; - if (error != nil) { - connectionStatus = ConnectionStatus(message: error!.localizedDescription, color: NSColor.red) - } else if let httpResponse = response as? HTTPURLResponse { - let statusCode = httpResponse.statusCode - print("status code " + String(describing: statusCode) + " on host " + (url.absoluteString)) - - connectionStatus = ConnectionStatus( - message: (statusCode == 200) ? "Connection established" : "Host returned invalid response", - color: (statusCode == 200) ? NSColor.green : NSColor.red) - } else { - connectionStatus = ConnectionStatus(message: "Host returned invalid response", color: NSColor.red) - } - - DispatchQueue.main.async { - print(connectionStatus.message) - self.onConnectionStatusChange(status: connectionStatus) - } - } - task.resume() - } - @IBAction func hostPortActionHandler(_ sender: NSTextField) { let hostPort = sender.integerValue print("hostPortActionHandler", hostPort) diff --git a/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib b/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib new file mode 100644 index 0000000..a00a475 --- /dev/null +++ b/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift b/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift new file mode 100644 index 0000000..7c2500a --- /dev/null +++ b/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift @@ -0,0 +1,83 @@ +// +// StatusBarMenuController.swift +// Shortcuts for Pi-hole +// +// Created by Lukas Wolfsteiner on 20.10.18. +// Copyright © 2018 Lukas Wolfsteiner. All rights reserved. +// + +import Cocoa + +class MainMenuController: NSObject, NSMenuDelegate { + + @IBOutlet weak var statusBarMenu: NSMenu! + let statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + + @IBOutlet weak var statusMenuItem: NSMenuItem! + @IBOutlet weak var aboutMenuItem: NSMenuItem! + @IBOutlet weak var preferencesMenuItem: NSMenuItem! + @IBOutlet weak var quitMenuItem: NSMenuItem! + + let mainWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateInitialController() as! MainWindowController + + override init() { + super.init() + } + + override func awakeFromNib() { + /* + if let button = statusBarItem.button { + button.image = NSImage(named: "StatusBarButtonImage") + button.menu = statusBarMenu + button.target = self + + print("awaitFromNib: created menu") + } + */ + + statusBarItem.image = NSImage(named: "StatusBarButtonImage") + statusBarItem.menu = statusBarMenu + + statusBarMenu.delegate = self + + performPiHoleAction(action: PiHoleAction.Status) + } + + @IBAction func enablePermanentlyMenuItemActionHandler(_ sender: NSMenuItem) { + performPiHoleAction(action: PiHoleAction.Enable) + } + + @IBAction func disablePermanentlyMenuItemActionHandler(_ sender: NSMenuItem) { + performPiHoleAction(action: PiHoleAction.Disable) + } + + func performPiHoleAction(action: PiHoleAction) { + if PiHoleProxy.getConfigStatus().color == NSColor.green { + self.dispatchStatusMenuItemUpdate(withTitle: "Pi-hole Status: Requesting...") + + PiHoleProxy.performActionRequest(PiHoleAction.Status, onSuccess: { (status) in + self.dispatchStatusMenuItemUpdate(withTitle: "Pi-hole Status: " + status) + }) { (error) in self.dispatchStatusMenuItemUpdate(withTitle: "Error: No connection.") } + } else { + self.dispatchStatusMenuItemUpdate(withTitle: "Error: Configuration invalid.") + } + } + + func dispatchStatusMenuItemUpdate(withTitle: String) { + DispatchQueue.main.async { + self.statusMenuItem.title = withTitle + } + } + + @IBAction func aboutMenuItemActionHandler(_ sender: NSMenuItem) { + // TODO + } + + @IBAction func preferencesMenuItemActionHandler(_ sender: NSMenuItem) { + mainWindowController.showWindow(self) + } + + @IBAction func quitMenuItemActionHandler(_ sender: NSMenuItem) { + NSApplication.shared.terminate(self) + } +} From b50f8626b56162f8c9e79c425728f16fda1c65bd Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sun, 21 Oct 2018 02:10:48 +0200 Subject: [PATCH 14/38] Added disabled status menu item to status bar menu --- .../MainWindow/Main.storyboard | 2 +- .../MainConnectionViewController.swift | 2 +- Shortcuts for Pi-hole/PiHoleProxy.swift | 20 ++++++++++--------- .../StatusBarMenu/MainMenu.xib | 16 +++++++++------ .../StatusBarMenu/MainMenuController.swift | 6 ++++++ 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index e463d13..9b82258 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -498,7 +498,7 @@ - + diff --git a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift index 1b54403..d821021 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift @@ -28,7 +28,7 @@ class MainConnectionViewController: NSViewController { // config valid if connectionStatus!.color == NSColor.green { // display url - let url = PiHoleProxy.getBaseUrl(action: PiHoleAction.Status) + let url = PiHoleProxy.getBaseUrl(action: PiHoleAction.Enable) exampleRequestUrlTextField.stringValue = url!.absoluteString statusMessageLabelOutlet.stringValue = "Press connect to verify" diff --git a/Shortcuts for Pi-hole/PiHoleProxy.swift b/Shortcuts for Pi-hole/PiHoleProxy.swift index 025986c..68f49ce 100644 --- a/Shortcuts for Pi-hole/PiHoleProxy.swift +++ b/Shortcuts for Pi-hole/PiHoleProxy.swift @@ -33,16 +33,18 @@ class PiHoleProxy: NSObject { let apiKey = GeneralPreferences.getApiKey() let base = requestProtocol + "://" + hostAddress! + ":" + String(hostPort) - let path: String = "/admin/api.php?auth=" + apiKey - - var urlString = base + path - if (action == PiHoleAction.Enable) { - urlString = urlString + "&enable" - } else if (action == PiHoleAction.Disable) { - urlString = urlString + "&disable" + let path: String = "/admin/api.php" + let params: String = "?auth=" + apiKey + + switch action { + case PiHoleAction.Enable: + return URL(string: base + path + params + "&enable") + case PiHoleAction.Disable: + return URL(string: base + path + params + "&disable") + default: + // PiHoleAction.Status + return URL(string: base + path) } - - return URL(string: urlString) } public static func getConfigStatus() -> ConnectionStatus { diff --git a/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib b/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib index a00a475..1f20a95 100644 --- a/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib +++ b/Shortcuts for Pi-hole/StatusBarMenu/MainMenu.xib @@ -27,10 +27,15 @@ + + + + + - + - + @@ -51,9 +56,9 @@ - + - + @@ -75,8 +80,7 @@ - - + diff --git a/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift b/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift index 7c2500a..2050c0d 100644 --- a/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift +++ b/Shortcuts for Pi-hole/StatusBarMenu/MainMenuController.swift @@ -40,6 +40,12 @@ class MainMenuController: NSObject, NSMenuDelegate { statusBarMenu.delegate = self + // refresh status on creation + performPiHoleAction(action: PiHoleAction.Status) + } + + @IBAction func refreshMenuItemActionHandler(_ sender: NSMenuItem) { + print("refreshMenuItemActionHandler") performPiHoleAction(action: PiHoleAction.Status) } From 2552b178ad238bf3bfeda4778869c6ff5066dfb0 Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Sun, 21 Oct 2018 03:51:38 +0200 Subject: [PATCH 15/38] Fixed invalid vertical constraints --- .../MainWindow/Main.storyboard | 145 +++++++++--------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/Shortcuts for Pi-hole/MainWindow/Main.storyboard b/Shortcuts for Pi-hole/MainWindow/Main.storyboard index 9b82258..8006d23 100644 --- a/Shortcuts for Pi-hole/MainWindow/Main.storyboard +++ b/Shortcuts for Pi-hole/MainWindow/Main.storyboard @@ -9,11 +9,12 @@ - + - + + @@ -24,7 +25,7 @@ - + @@ -36,8 +37,8 @@ - - + + @@ -50,7 +51,7 @@ - + @@ -58,11 +59,11 @@ - - + + - + @@ -70,8 +71,8 @@ - - + + @@ -172,10 +173,13 @@ + + + - + @@ -183,7 +187,7 @@ - + @@ -251,6 +255,9 @@ + + + @@ -286,7 +293,7 @@ - + @@ -298,7 +305,7 @@ - + @@ -310,6 +317,7 @@ + @@ -325,7 +333,7 @@ - + @@ -333,26 +341,26 @@ - + - - + + - + - + - - + + @@ -369,57 +377,20 @@ + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + @@ -598,10 +632,12 @@ + - + + @@ -614,6 +650,8 @@ + + diff --git a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift index 90f5ff4..d18da56 100644 --- a/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift +++ b/Shortcuts for Pi-hole/MainWindow/MainConnectionViewController.swift @@ -14,7 +14,7 @@ class MainConnectionViewController: NSViewController { super.viewDidLoad() // Do view setup here. - self.displayBuiltUrl() + _ = self.displayBuiltUrl() } @IBOutlet weak var coloredStatusViewOutlet: ColoredStatusView! From befeb7f7973abb4d9f192ed3b7a9ac8678d6a77d Mon Sep 17 00:00:00 2001 From: Lukas Wolfsteiner Date: Mon, 22 Oct 2018 15:58:56 +0200 Subject: [PATCH 25/38] Fixed invalid description position --- Shortcuts for Pi-hole/Main.storyboard | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Shortcuts for Pi-hole/Main.storyboard b/Shortcuts for Pi-hole/Main.storyboard index baa87ad..b0bf65b 100644 --- a/Shortcuts for Pi-hole/Main.storyboard +++ b/Shortcuts for Pi-hole/Main.storyboard @@ -563,7 +563,7 @@ - + @@ -571,10 +571,11 @@ - - + + - Shortcuts for Pi-hole is a small menu bar application that lives in your status bar. + Shortcuts for Pi-hole is a small menu bar application that lives in your status bar. + It provides quick actions for managing and monitoring your Pi-hole® instance. @@ -584,7 +585,7 @@ It provides quick actions for managing and monitoring your Pi-hole® instance. - + @@ -592,10 +593,10 @@ It provides quick actions for managing and monitoring your Pi-hole® instance. - +