From 5dbd05fdfb7f38f6dec2f32bfea15376ae68f510 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Sat, 13 Nov 2021 20:50:17 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20option=20to=20auto-restart=20?= =?UTF-8?q?services=20(#32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 8 +- phpmon/Domain/Core/Base.lproj/Main.storyboard | 56 ++++++++++-- phpmon/Domain/Menu/MainMenu.swift | 4 + phpmon/Domain/Preferences/Preferences.swift | 87 +++++++++++-------- phpmon/Domain/Preferences/PrefsVC.swift | 19 ++++ phpmon/Localizable.strings | 7 ++ 6 files changed, 133 insertions(+), 48 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 9ca7cff..8d53e65 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -647,7 +647,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -655,7 +655,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 3.5.0; + MARKETING_VERSION = 4.0; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -671,7 +671,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -679,7 +679,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 3.5.0; + MARKETING_VERSION = 4.0; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/phpmon/Domain/Core/Base.lproj/Main.storyboard b/phpmon/Domain/Core/Base.lproj/Main.storyboard index e1e95d6..5d786e3 100644 --- a/phpmon/Domain/Core/Base.lproj/Main.storyboard +++ b/phpmon/Domain/Core/Base.lproj/Main.storyboard @@ -84,8 +84,8 @@ - - + + - + @@ -165,7 +165,7 @@ Gw - + @@ -184,7 +184,7 @@ Gw - + + + + + + + + + + + + + + + + + + + + + + + @@ -214,7 +245,10 @@ Gw + + + @@ -222,29 +256,33 @@ Gw - + + + + + - + diff --git a/phpmon/Domain/Menu/MainMenu.swift b/phpmon/Domain/Menu/MainMenu.swift index fa92dfa..5394c4b 100644 --- a/phpmon/Domain/Menu/MainMenu.swift +++ b/phpmon/Domain/Menu/MainMenu.swift @@ -257,6 +257,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { @objc func toggleExtension(sender: ExtensionMenuItem) { waitAndExecute { sender.phpExtension?.toggle() + + if Preferences.preferences[.autoServiceRestartAfterExtensionToggle] as! Bool == true { + Actions.restartPhpFpm() + } } } diff --git a/phpmon/Domain/Preferences/Preferences.swift b/phpmon/Domain/Preferences/Preferences.swift index 47b1b08..72b94d8 100644 --- a/phpmon/Domain/Preferences/Preferences.swift +++ b/phpmon/Domain/Preferences/Preferences.swift @@ -9,57 +9,71 @@ import Foundation enum PreferenceName: String { + case wasLaunchedBefore = "launched_before" case shouldDisplayDynamicIcon = "use_dynamic_icon" case fullPhpVersionDynamicIcon = "full_php_in_menu_bar" + case autoServiceRestartAfterExtensionToggle = "auto_restart_after_extension_toggle" case globalHotkey = "global_hotkey" } class Preferences { + // MARK: - Singleton + + static var shared = Preferences() + + var cachedPreferences: [PreferenceName: Any?] + + public init() { + Preferences.handleFirstTimeLaunch() + self.cachedPreferences = Self.cache() + } + + // MARK: - First Time Run + + /** + Note: macOS seems to cache plist values in memory as well as in files. + You can find the persisted configuration file in: ~/Library/Preferences/com.nicoverbruggen.phpmon.plist + + To clear the cache, and get a first-run experience you may need to run: + ``` + defaults delete com.nicoverbruggen.phpmon + killall cfprefsd + ``` + */ static func handleFirstTimeLaunch() { - let launchedBefore = UserDefaults.standard.bool(forKey: "launched_before") + UserDefaults.standard.register(defaults: [ + PreferenceName.shouldDisplayDynamicIcon.rawValue: true, + PreferenceName.fullPhpVersionDynamicIcon.rawValue: false, + PreferenceName.autoServiceRestartAfterExtensionToggle.rawValue: true + ]) - if launchedBefore { + if UserDefaults.standard.bool(forKey: PreferenceName.wasLaunchedBefore.rawValue) { return } - - // Set sensible defaults - UserDefaults.standard.setValue(true, forKey: PreferenceName.shouldDisplayDynamicIcon.rawValue) - UserDefaults.standard.setValue(false, forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) - UserDefaults.standard.setValue(true, forKey: "launched_before") - UserDefaults.standard.synchronize() - print("Saving first-time preferences!") + UserDefaults.standard.setValue(true, forKey: PreferenceName.wasLaunchedBefore.rawValue) + UserDefaults.standard.synchronize() } - static func handleMissingPreferences() { - var migrated = false - - // Any defaults that need to be adopted in case they are missing? - // If any new preferences are added in updates, they should get a default value here! - if UserDefaults.standard.value(forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) == nil { - UserDefaults.standard.setValue(false, forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) - migrated = true - } - - if migrated { - UserDefaults.standard.synchronize() - } - } - - static func retrieve() -> [PreferenceName: Any] { - Preferences.handleFirstTimeLaunch() - Preferences.handleMissingPreferences() - - return [ - .shouldDisplayDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.shouldDisplayDynamicIcon.rawValue) as Any, - .fullPhpVersionDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) as Any, - .globalHotkey: UserDefaults.standard.string(forKey: PreferenceName.globalHotkey.rawValue) as Any, - ] - } + // MARK: - API static var preferences: [PreferenceName: Any?] { - return Preferences.retrieve() + return Self.shared.cachedPreferences + } + + // MARK: - Internal Functionality + + static func cache() -> [PreferenceName: Any] { + return [ + // Part 1: Always Booleans + .shouldDisplayDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.shouldDisplayDynamicIcon.rawValue) as Any, + .fullPhpVersionDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) as Any, + .autoServiceRestartAfterExtensionToggle: UserDefaults.standard.bool(forKey: PreferenceName.autoServiceRestartAfterExtensionToggle.rawValue) as Any, + + // Part 2: Always Strings + .globalHotkey: UserDefaults.standard.string(forKey: PreferenceName.globalHotkey.rawValue) as Any, + ] } static func update(_ preference: PreferenceName, value: Any?) { @@ -69,6 +83,9 @@ class Preferences { UserDefaults.standard.setValue(value, forKey: preference.rawValue) } UserDefaults.standard.synchronize() + + // Update the preferences cache in memory! + Preferences.shared.cachedPreferences = Preferences.cache() } } diff --git a/phpmon/Domain/Preferences/PrefsVC.swift b/phpmon/Domain/Preferences/PrefsVC.swift index b19b654..66ec9d0 100644 --- a/phpmon/Domain/Preferences/PrefsVC.swift +++ b/phpmon/Domain/Preferences/PrefsVC.swift @@ -14,6 +14,7 @@ class PrefsVC: NSViewController { // Labels on the left @IBOutlet weak var leftLabelDynamicIcon: NSTextField! + @IBOutlet weak var leftLabelServices: NSTextField! @IBOutlet weak var leftLabelGlobalShortcut: NSTextField! // Dynamic icon @@ -24,6 +25,10 @@ class PrefsVC: NSViewController { @IBOutlet weak var buttonDisplayFullPhpVersion: NSButton! @IBOutlet weak var labelDisplayFullPhpVersion: NSTextField! + // Auto-restart services + @IBOutlet weak var buttonAutoRestartServices: NSButton! + @IBOutlet weak var labelAutoRestartServices: NSTextField! + // Shortcut @IBOutlet weak var buttonSetShortcut: NSButton! @IBOutlet weak var buttonClearShortcut: NSButton! @@ -76,6 +81,11 @@ class PrefsVC: NSViewController { buttonDisplayFullPhpVersion.title = "prefs.display_full_php_version".localized labelDisplayFullPhpVersion.stringValue = "prefs.display_full_php_version_desc".localized + // Services + leftLabelServices.stringValue = "prefs.services".localized + buttonAutoRestartServices.title = "prefs.auto_restart_services_title".localized + labelAutoRestartServices.stringValue = "prefs_auto_restart_services_desc".localized + // Global Shortcut leftLabelGlobalShortcut.stringValue = "prefs.global_shortcut".localized labelShortcut.stringValue = "prefs.shortcut_desc".localized @@ -98,6 +108,11 @@ class PrefsVC: NSViewController { self.buttonDisplayFullPhpVersion.state = shouldDisplay ? .on : .off } + func loadAutoRestartServicesFromPreferences() { + let shouldDisplay = Preferences.preferences[.autoServiceRestartAfterExtensionToggle] as! Bool == true + self.buttonAutoRestartServices.state = shouldDisplay ? .on : .off + } + // MARK: - Actions @IBAction func toggledDynamicIcon(_ sender: Any) { @@ -110,6 +125,10 @@ class PrefsVC: NSViewController { MainMenu.shared.refreshIcon() } + @IBAction func toggledAutoRestartServices(_ sender: Any) { + Preferences.update(.autoServiceRestartAfterExtensionToggle, value: buttonAutoRestartServices.state == .on) + } + // MARK: - Shortcut Preference // Adapted from: https://dev.to/mitchartemis/creating-a-global-configurable-shortcut-for-macos-apps-in-swift-25e9 diff --git a/phpmon/Localizable.strings b/phpmon/Localizable.strings index 9af6834..885e8c9 100644 --- a/phpmon/Localizable.strings +++ b/phpmon/Localizable.strings @@ -52,6 +52,10 @@ "prefs.global_shortcut" = "Global shortcut:"; "prefs.dynamic_icon" = "Dynamic icon:"; +"prefs.services" = "Services:"; + +"prefs.auto_restart_services_title" = "Auto-restart PHP-FPM"; +"prefs_auto_restart_services_desc" = "When checked, will automatically restart PHP-FPM when\nyou check or uncheck an extension. Slightly slower when enabled, \nbut this applies the extension change immediately for all sites \nyou're serving, no need to restart PHP-FPM manually."; "prefs.dynamic_icon_title" = "Display dynamic icon in menu bar"; "prefs.dynamic_icon_desc" = "If you uncheck this box, the truck icon will always be visible.\nIf checked, it will display the major version number of the\ncurrently linked PHP version."; @@ -69,6 +73,9 @@ "notification.version_changed_title" = "PHP %@ now active"; "notification.version_changed_desc" = "PHP Monitor has switched to PHP %@."; +"notification.php_fpm_restarted" = "PHP-FPM automatically restarted"; +"notification.php_fpm_restarted_desc" = "You toggled an extension, so PHP-FPM was automatically restarted."; + "notification.services_stopped" = "Valet services stopped"; "notification.services_stopped_desc" = "All services have been successfully stopped.";