1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2026-03-26 06:00:07 +01:00

♻️ Rework interapp handling, ensure preferences UI observes changes

This commit is contained in:
2026-02-06 19:10:38 +01:00
parent 228d85a861
commit 54d1ef10c5
9 changed files with 70 additions and 10 deletions

View File

@@ -11,5 +11,6 @@ import Foundation
class Events {
static let ServicesUpdated = Notification.Name("ServicesUpdated")
static let PreferencesUpdated = Notification.Name("PreferencesUpdated")
}

View File

@@ -105,6 +105,9 @@ class App {
/** The window controller of the PHP extension manager window. */
var phpExtensionManagerWindowController: PhpExtensionManagerWindowController?
/** URL that was received before the app finished booting. Will be processed once the startup procedure completes. */
var deferredURL: URL?
/** List of detected (installed) applications that PHP Monitor can work with. */
var detectedApplications: [Application] = []

View File

@@ -17,17 +17,40 @@ extension AppDelegate {
application URL. You can use the `phpmon://` protocol to communicate with the app.
At this time you can trigger the site list using Alfred (or some other application)
by opening the following URL: `phpmon://list`.
by opening the following URL: `phpmon://list`. Various other commands are also made
available via the `InterApp` class, which is where all commands and their different
interactions are declared.
Please note that PHP Monitor needs to be running in the background for this to work.
Please note that PHP Monitor needs to be running in the background for this to work,
or the app will launch and the command will be deferred until the app is ready.
*/
@MainActor func application(_ application: NSApplication, open urls: [URL]) {
guard Startup.hasFinishedBooting else {
return deferURLs(urls)
}
handleURLs(urls)
}
@MainActor func deferURLs(_ urls: [URL]) {
Log.info("App has not finished booting, deferring phpmon:// command...")
App.shared.deferredURL = urls.first
}
@MainActor func handleURLs(_ urls: [URL]) {
if !Preferences.isEnabled(.allowProtocolForIntegrations) {
if UserDefaults.standard.bool(forKey: PersistentAppState.didPromptForIntegrations.rawValue) {
// First, we'll check if we already prompted for integrations.
// If we have, we will not respond to the commands at all.
if UserDefaults.standard.bool(
forKey: PersistentAppState.didPromptForIntegrations.rawValue
) {
Log.info("Acting on commands via phpmon:// has been disabled.")
return
}
// However, if that isn't the case, we will prompt the user about integrations,
// which will give the user a chance to approve the command regardless.
Log.info("Acting on commands via phpmon:// has been disabled. Prompting user...")
if !promptToEnableIntegrations() {
return
@@ -58,7 +81,7 @@ extension AppDelegate {
return false
}
Preferences.update(.allowProtocolForIntegrations, value: true)
Preferences.update(.allowProtocolForIntegrations, value: true, notify: true)
return true
}

View File

@@ -124,6 +124,12 @@ extension Startup {
Startup.hasFinishedBooting = true
Log.info("PHP Monitor is ready to serve!")
// Process the last URL that arrived during startup
if let url = App.shared.deferredURL {
AppDelegate.instance.handleURLs([url])
App.shared.deferredURL = nil
}
// Enable the main menu item
MainMenu.shared.statusItem.button?.isEnabled = true

View File

@@ -24,7 +24,7 @@ extension Valet {
)
.withPrimary(text: "generic.ok".localized)
.withTertiary(text: "alert.do_not_tell_again".localized, action: { alert in
Preferences.update(.warnAboutNonStandardTLD, value: false)
Preferences.update(.warnAboutNonStandardTLD, value: false, notify: true)
alert.close(with: .alertThirdButtonReturn)
})
.show(urgency: .urgentRequestAttention)

View File

@@ -168,7 +168,7 @@ class Preferences {
})
}
static func update(_ preference: PreferenceName, value: Any?) {
static func update(_ preference: PreferenceName, value: Any?, notify: Bool = false) {
if value == nil {
UserDefaults.standard.removeObject(forKey: preference.rawValue)
} else {
@@ -178,5 +178,9 @@ class Preferences {
// Update the preferences cache in memory!
App.shared.container.preferences.cachedPreferences = Preferences.cache()
if notify {
NotificationCenter.default.post(name: Events.PreferencesUpdated, object: nil)
}
}
}

View File

@@ -65,6 +65,15 @@ class CheckboxPreferenceBehavior: CheckboxPreferenceViewBehavior {
self.preference = preference
self.button = button
self.button.state = Preferences.isEnabled(self.preference) ? .on : .off
NotificationCenter.default.addObserver(
self, selector: #selector(refreshState),
name: Events.PreferencesUpdated, object: nil
)
}
@objc func refreshState() {
self.button.state = Preferences.isEnabled(self.preference) ? .on : .off
}
public func toggled(checked: Bool) {

View File

@@ -73,9 +73,23 @@ class SelectPreferenceView: NSView, XibLoadable {
view.preference = preference
view.action = action
NotificationCenter.default.addObserver(
view, selector: #selector(view.refreshState),
name: Events.PreferencesUpdated, object: nil
)
return view
}
@objc func refreshState() {
let value = Preferences.preferences[preference] as! String
self.options.enumerated().forEach { option in
if option.element.value == value {
self.popupButton.selectItem(at: option.offset)
}
}
}
@IBAction func valueChanged(_ sender: Any) {
let index = self.popupButton.indexOfSelectedItem
Preferences.update(self.preference, value: self.options[index].value)

View File

@@ -954,8 +954,8 @@ PHP Monitor will tell Valet to unsecure and re-secure all expired domains for yo
// THIRD-PARTY INTEGRATIONS
"alert.enable_integrations.title" = "An external application is trying to communicate with PHP Monitor";
"alert.enable_integrations.subtitle" = "Do you want to allow third-party integrations (like Alfred or Raycast) to control PHP Monitor via the `phpmon://` protocol?\n\nThis notice appears because PHP Monitor just received an external command. If you triggered this intentionally, using a third-party app like Alfred or Raycast, it is safe to allow this.\n\nYou can change this setting later in Preferences.";
"alert.enable_integrations.desc" = "If you did not trigger this via Alfred or Raycast, there may be another application trying to control PHP Monitor. In that case, I recommend keeping this integration turned off, unless you are fine with another third party app controlling PHP Monitor for you, which could present a security risk.";
"alert.enable_integrations.ok" = "Allow";
"alert.enable_integrations.title" = "An external application is trying to communicate with PHP Monitor. Do you want third-party applications to be able to communicate with PHP Monitor?";
"alert.enable_integrations.subtitle" = "This notice appears because PHP Monitor just received an external command, and this feature is disabled by default. If you triggered this intentionally, using a third-party app like Alfred or Raycast, it is normally safe to allow this.\n\nYou can change this setting later in Preferences, you will be asked this question only once.";
"alert.enable_integrations.desc" = "If you did not trigger this via Alfred or Raycast, there may be another application trying to control PHP Monitor.\n\nIn such a case, I recommend keeping this integration turned off, unless you are fine with another third party app controlling PHP Monitor for you, which could present a potential security risk.";
"alert.enable_integrations.ok" = "Allow Integrations";
"alert.enable_integrations.cancel" = "Don't Allow";