From 4855c14d285e8f4776b962bd821e60c65618c2e3 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Wed, 7 Sep 2022 20:31:26 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20Preferences=20&?= =?UTF-8?q?=20PreferenceName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also added a few new preferences related to toggling specific menu items based on your personal choices. (These new settings still need to be added to the UI.) --- PHP Monitor.xcodeproj/project.pbxproj | 6 + phpmon/Domain/Preferences/CustomPrefs.swift | 54 ++++++ .../Domain/Preferences/PreferenceName.swift | 102 +++++++++++ phpmon/Domain/Preferences/Preferences.swift | 166 +++--------------- 4 files changed, 189 insertions(+), 139 deletions(-) create mode 100644 phpmon/Domain/Preferences/PreferenceName.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 109f7eb..3134f42 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -130,6 +130,8 @@ C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; }; C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; }; C44F868E2835BD8D005C353A /* phpmon-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C44F868D2835BD8D005C353A /* phpmon-config.json */; }; + C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450C8C528C919EC002A2B4B /* PreferenceName.swift */; }; + C450C8C728C919EC002A2B4B /* PreferenceName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450C8C528C919EC002A2B4B /* PreferenceName.swift */; }; C459B4BD27F6093700E9B4B4 /* nginx-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */; }; C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; @@ -400,6 +402,7 @@ C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = ""; }; C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Async.swift"; sourceTree = ""; }; C44F868D2835BD8D005C353A /* phpmon-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "phpmon-config.json"; sourceTree = ""; }; + C450C8C528C919EC002A2B4B /* PreferenceName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceName.swift; sourceTree = ""; }; C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-proxy.test"; sourceTree = ""; }; C45E76132854A65300B4FE0C /* ServicesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesManager.swift; sourceTree = ""; }; C463E37F284930EE00422731 /* PresetHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresetHelper.swift; sourceTree = ""; }; @@ -520,6 +523,7 @@ C4998F092617633900B2526E /* PreferencesWindowController.swift */, C4FACE7F288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift */, 5420395826135DC100FB00FA /* PrefsVC.swift */, + C450C8C528C919EC002A2B4B /* PreferenceName.swift */, 5420395E2613607600FB00FA /* Preferences.swift */, C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */, C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */, @@ -1323,6 +1327,7 @@ C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, 54FCFD30276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */, + C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */, C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */, C4F2E43A2752F7D00020E974 /* PhpInstallation.swift in Sources */, C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */, @@ -1497,6 +1502,7 @@ C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */, 54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */, C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */, + C450C8C728C919EC002A2B4B /* PreferenceName.swift in Sources */, C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */, C485707B28BF458900539B36 /* VersionPopoverView.swift in Sources */, C485706E28BF451C00539B36 /* OnboardingWindowController.swift in Sources */, diff --git a/phpmon/Domain/Preferences/CustomPrefs.swift b/phpmon/Domain/Preferences/CustomPrefs.swift index 6f8cec4..22d2c24 100644 --- a/phpmon/Domain/Preferences/CustomPrefs.swift +++ b/phpmon/Domain/Preferences/CustomPrefs.swift @@ -39,3 +39,57 @@ struct CustomPrefs: Decodable { case environmentVariables = "export" } } + +extension Preferences { + func loadCustomPreferences() { + // Ensure the configuration directory is created if missing + Shell.run("mkdir -p ~/.config/phpmon") + + // Move the legacy file + moveOutdatedConfigurationFile() + + // Attempt to load the file if it exists + let url = URL(fileURLWithPath: "\(Paths.homePath)/.config/phpmon/config.json") + if Filesystem.fileExists(url.path) { + + Log.info("A custom ~/.config/phpmon/config.json file was found. Attempting to parse...") + loadCustomPreferencesFile(url) + } else { + Log.info("There was no /.config/phpmon/config.json file to be loaded.") + } + } + + func moveOutdatedConfigurationFile() { + if Filesystem.fileExists("~/.phpmon.conf.json") && !Filesystem.fileExists("~/.config/phpmon/config.json") { + Log.info("An outdated configuration file was found. Moving it...") + Shell.run("cp ~/.phpmon.conf.json ~/.config/phpmon/config.json") + Log.info("The configuration file was copied successfully!") + } + } + + func loadCustomPreferencesFile(_ url: URL) { + do { + customPreferences = try JSONDecoder().decode( + CustomPrefs.self, + from: try! String(contentsOf: url, encoding: .utf8).data(using: .utf8)! + ) + + Log.info("The ~/.config/phpmon/config.json file was successfully parsed.") + + if customPreferences.hasPresets() { + Log.info("There are \(customPreferences.presets!.count) custom presets.") + } + + if customPreferences.hasServices() { + Log.info("There are custom services: \(customPreferences.services!)") + } + + if customPreferences.hasEnvironmentVariables() { + Log.info("Configuring the additional exports...") + Shell.user.exports = customPreferences.getEnvironmentVariables() + } + } catch { + Log.warn("The ~/.config/phpmon/config.json file seems to be missing or malformed.") + } + } +} diff --git a/phpmon/Domain/Preferences/PreferenceName.swift b/phpmon/Domain/Preferences/PreferenceName.swift new file mode 100644 index 0000000..98ed039 --- /dev/null +++ b/phpmon/Domain/Preferences/PreferenceName.swift @@ -0,0 +1,102 @@ +// +// PreferenceName.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 07/09/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +/** + These are the keys used for every preference in the app. + */ +enum PreferenceName: String { + // FIRST-TIME LAUNCH + case wasLaunchedBefore = "launched_before" + + // GENERAL + case autoServiceRestartAfterExtensionToggle = "auto_restart_after_extension_toggle" + case autoComposerGlobalUpdateAfterSwitch = "auto_composer_global_update_after_switch" + case allowProtocolForIntegrations = "allow_protocol_for_integrations" + case globalHotkey = "global_hotkey" + case automaticBackgroundUpdateCheck = "backgroundUpdateCheck" + case showPhpDoctorSuggestions = "show_php_doctor_suggestions" + + // APPEARANCE + case shouldDisplayDynamicIcon = "use_dynamic_icon" + case iconTypeToDisplay = "icon_type_to_display" + case fullPhpVersionDynamicIcon = "full_php_in_menu_bar" + + // NOTIFICATIONS + case notifyAboutVersionChange = "notify_about_version_change" + case notifyAboutPhpFpmRestart = "notify_about_php_fpm_restart" + case notifyAboutServices = "notify_about_services_restart" + case notifyAboutPresets = "notify_about_presets" + case notifyAboutSecureToggle = "notify_about_secure_toggle" + case notifyAboutGlobalComposerStatus = "notify_about_composer_status" + + // MENU CUSTOMIZATION + case displayVersionSwitcher = "display_version_switcher" + case displayServicesManager = "display_services_manager" + case displayValetConfigFinder = "display_valet_config_finder" + case displayPhpConfigFinder = "display_php_config_finder" + case displayComposerToolkit = "display_composer_toolkit" + case displayLimitsWidget = "display_limits_widget" + case displayExtensions = "display_extensions" + + /** + What type of data each preference contains. + */ + static var mapping: [PreferenceType: [PreferenceName]] = [ + .boolean: [ + // Preferences + .shouldDisplayDynamicIcon, + .fullPhpVersionDynamicIcon, + .autoServiceRestartAfterExtensionToggle, + .autoComposerGlobalUpdateAfterSwitch, + .allowProtocolForIntegrations, + .automaticBackgroundUpdateCheck, + .showPhpDoctorSuggestions, + + // Notifications + .notifyAboutVersionChange, + .notifyAboutPhpFpmRestart, + .notifyAboutServices, + .notifyAboutPresets, + .notifyAboutSecureToggle, + .notifyAboutGlobalComposerStatus, + + // UI Preferences + .displayVersionSwitcher, + .displayServicesManager, + .displayValetConfigFinder, + .displayPhpConfigFinder, + .displayComposerToolkit, + .displayLimitsWidget, + .displayExtensions + ], + .string: [ + .globalHotkey, + .iconTypeToDisplay + ] + ] +} + +enum PreferenceType { + case boolean, string +} + +/** + These are retired preferences that, if present, should be migrated. + */ +enum RetiredPreferenceName: String { + case shouldDisplayPhpHintInIcon = "add_php_to_icon" +} + +/** + These are internal stats. They NEVER get shared. + */ +enum InternalStats: String { + case launchCount = "times_launched" + case switchCount = "times_switched_versions" + case didSeeSponsorEncouragement = "did_see_sponsor_encouragement" +} diff --git a/phpmon/Domain/Preferences/Preferences.swift b/phpmon/Domain/Preferences/Preferences.swift index 1b3e4fd..b6eddbf 100644 --- a/phpmon/Domain/Preferences/Preferences.swift +++ b/phpmon/Domain/Preferences/Preferences.swift @@ -8,51 +8,6 @@ import Foundation -/** - These are the keys used for every preference in the app. - */ -enum PreferenceName: String { - // FIRST-TIME LAUNCH - case wasLaunchedBefore = "launched_before" - - // GENERAL - case autoServiceRestartAfterExtensionToggle = "auto_restart_after_extension_toggle" - case autoComposerGlobalUpdateAfterSwitch = "auto_composer_global_update_after_switch" - case allowProtocolForIntegrations = "allow_protocol_for_integrations" - case globalHotkey = "global_hotkey" - case automaticBackgroundUpdateCheck = "backgroundUpdateCheck" - case showPhpDoctorSuggestions = "show_php_doctor_suggestions" - - // APPEARANCE - case shouldDisplayDynamicIcon = "use_dynamic_icon" - case iconTypeToDisplay = "icon_type_to_display" - case fullPhpVersionDynamicIcon = "full_php_in_menu_bar" - - // NOTIFICATIONS - case notifyAboutVersionChange = "notify_about_version_change" - case notifyAboutPhpFpmRestart = "notify_about_php_fpm_restart" - case notifyAboutServices = "notify_about_services_restart" - case notifyAboutPresets = "notify_about_presets" - case notifyAboutSecureToggle = "notify_about_secure_toggle" - case notifyAboutGlobalComposerStatus = "notify_about_composer_status" -} - -/** - These are retired preferences that, if present, should be migrated. - */ -enum RetiredPreferenceName: String { - case shouldDisplayPhpHintInIcon = "add_php_to_icon" -} - -/** - These are internal stats. They NEVER get shared. - */ -enum InternalStats: String { - case launchCount = "times_launched" - case switchCount = "times_switched_versions" - case didSeeSponsorEncouragement = "did_see_sponsor_encouragement" -} - class Preferences { // MARK: - Singleton @@ -66,7 +21,12 @@ class Preferences { public init() { Preferences.handleFirstTimeLaunch() cachedPreferences = Self.cache() - customPreferences = CustomPrefs(scanApps: [], presets: [], services: [], environmentVariables: [:]) + customPreferences = CustomPrefs( + scanApps: [], + presets: [], + services: [], + environmentVariables: [:] + ) loadCustomPreferences() } @@ -104,6 +64,15 @@ class Preferences { PreferenceName.notifyAboutSecureToggle.rawValue: true, PreferenceName.notifyAboutGlobalComposerStatus.rawValue: true, + /// Preferences: UI Preferences + PreferenceName.displayVersionSwitcher.rawValue: true, + PreferenceName.displayServicesManager.rawValue: true, + PreferenceName.displayValetConfigFinder.rawValue: true, + PreferenceName.displayPhpConfigFinder.rawValue: true, + PreferenceName.displayComposerToolkit.rawValue: true, + PreferenceName.displayLimitsWidget.rawValue: true, + PreferenceName.displayExtensions.rawValue: true, + /// Stats InternalStats.switchCount.rawValue: 0, InternalStats.launchCount.rawValue: 0, @@ -160,44 +129,18 @@ class Preferences { // MARK: - Internal Functionality - private 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, - .autoComposerGlobalUpdateAfterSwitch: UserDefaults.standard.bool( - forKey: PreferenceName.autoComposerGlobalUpdateAfterSwitch.rawValue) as Any, - .allowProtocolForIntegrations: UserDefaults.standard.bool( - forKey: PreferenceName.allowProtocolForIntegrations.rawValue) as Any, - .automaticBackgroundUpdateCheck: UserDefaults.standard.bool( - forKey: PreferenceName.automaticBackgroundUpdateCheck.rawValue) as Any, - .showPhpDoctorSuggestions: UserDefaults.standard.bool( - forKey: PreferenceName.showPhpDoctorSuggestions.rawValue) as Any, - - .notifyAboutVersionChange: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutVersionChange.rawValue) as Any, - .notifyAboutPhpFpmRestart: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutPhpFpmRestart.rawValue) as Any, - .notifyAboutServices: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutServices.rawValue) as Any, - .notifyAboutPresets: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutPresets.rawValue) as Any, - .notifyAboutSecureToggle: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutSecureToggle.rawValue) as Any, - .notifyAboutGlobalComposerStatus: UserDefaults.standard.bool( - forKey: PreferenceName.notifyAboutGlobalComposerStatus.rawValue) as Any, - - // Part 2: Always Strings - .globalHotkey: UserDefaults.standard.string( - forKey: PreferenceName.globalHotkey.rawValue) as Any, - .iconTypeToDisplay: UserDefaults.standard.string( - forKey: PreferenceName.iconTypeToDisplay.rawValue) as Any - ] + private static func cache() -> [PreferenceName: Any?] { + return Dictionary(uniqueKeysWithValues: PreferenceName.mapping + .flatMap { (key: PreferenceType, value: [PreferenceName]) in + value.map { preference -> (PreferenceName, Any?) in + return (preference, { () -> Any? in + switch key { + case .boolean: return UserDefaults.standard.bool(forKey: preference.rawValue) + case .string: return UserDefaults.standard.string(forKey: preference.rawValue) + } + }()) + } + }) } static func update(_ preference: PreferenceName, value: Any?) { @@ -211,59 +154,4 @@ class Preferences { // Update the preferences cache in memory! Preferences.shared.cachedPreferences = Preferences.cache() } - - // MARK: - Custom Preferences - - private func loadCustomPreferences() { - // Ensure the configuration directory is created if missing - Shell.run("mkdir -p ~/.config/phpmon") - - // Move the legacy file - moveOutdatedConfigurationFile() - - // Attempt to load the file if it exists - let url = URL(fileURLWithPath: "\(Paths.homePath)/.config/phpmon/config.json") - if Filesystem.fileExists(url.path) { - - Log.info("A custom ~/.config/phpmon/config.json file was found. Attempting to parse...") - loadCustomPreferencesFile(url) - } else { - Log.info("There was no /.config/phpmon/config.json file to be loaded.") - } - } - - private func moveOutdatedConfigurationFile() { - if Filesystem.fileExists("~/.phpmon.conf.json") && !Filesystem.fileExists("~/.config/phpmon/config.json") { - Log.info("An outdated configuration file was found. Moving it...") - Shell.run("cp ~/.phpmon.conf.json ~/.config/phpmon/config.json") - Log.info("The configuration file was copied successfully!") - } - } - - private func loadCustomPreferencesFile(_ url: URL) { - do { - customPreferences = try JSONDecoder().decode( - CustomPrefs.self, - from: try! String(contentsOf: url, encoding: .utf8).data(using: .utf8)! - ) - - Log.info("The ~/.config/phpmon/config.json file was successfully parsed.") - - if customPreferences.hasPresets() { - Log.info("There are \(customPreferences.presets!.count) custom presets.") - } - - if customPreferences.hasServices() { - Log.info("There are custom services: \(customPreferences.services!)") - } - - if customPreferences.hasEnvironmentVariables() { - Log.info("Configuring the additional exports...") - Shell.user.exports = customPreferences.getEnvironmentVariables() - } - } catch { - Log.warn("The ~/.config/phpmon/config.json file seems to be missing or malformed.") - } - } - }