mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2026-03-28 23:00:07 +01:00
♻️ Rework interapp handling, ensure preferences UI observes changes
This commit is contained in:
@@ -11,5 +11,6 @@ import Foundation
|
|||||||
class Events {
|
class Events {
|
||||||
|
|
||||||
static let ServicesUpdated = Notification.Name("ServicesUpdated")
|
static let ServicesUpdated = Notification.Name("ServicesUpdated")
|
||||||
|
static let PreferencesUpdated = Notification.Name("PreferencesUpdated")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ class App {
|
|||||||
/** The window controller of the PHP extension manager window. */
|
/** The window controller of the PHP extension manager window. */
|
||||||
var phpExtensionManagerWindowController: PhpExtensionManagerWindowController?
|
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. */
|
/** List of detected (installed) applications that PHP Monitor can work with. */
|
||||||
var detectedApplications: [Application] = []
|
var detectedApplications: [Application] = []
|
||||||
|
|
||||||
|
|||||||
@@ -17,17 +17,40 @@ extension AppDelegate {
|
|||||||
application URL. You can use the `phpmon://` protocol to communicate with the app.
|
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)
|
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]) {
|
@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 !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.")
|
Log.info("Acting on commands via phpmon:// has been disabled.")
|
||||||
return
|
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...")
|
Log.info("Acting on commands via phpmon:// has been disabled. Prompting user...")
|
||||||
if !promptToEnableIntegrations() {
|
if !promptToEnableIntegrations() {
|
||||||
return
|
return
|
||||||
@@ -58,7 +81,7 @@ extension AppDelegate {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
Preferences.update(.allowProtocolForIntegrations, value: true)
|
Preferences.update(.allowProtocolForIntegrations, value: true, notify: true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,12 @@ extension Startup {
|
|||||||
Startup.hasFinishedBooting = true
|
Startup.hasFinishedBooting = true
|
||||||
Log.info("PHP Monitor is ready to serve!")
|
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
|
// Enable the main menu item
|
||||||
MainMenu.shared.statusItem.button?.isEnabled = true
|
MainMenu.shared.statusItem.button?.isEnabled = true
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ extension Valet {
|
|||||||
)
|
)
|
||||||
.withPrimary(text: "generic.ok".localized)
|
.withPrimary(text: "generic.ok".localized)
|
||||||
.withTertiary(text: "alert.do_not_tell_again".localized, action: { alert in
|
.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)
|
alert.close(with: .alertThirdButtonReturn)
|
||||||
})
|
})
|
||||||
.show(urgency: .urgentRequestAttention)
|
.show(urgency: .urgentRequestAttention)
|
||||||
|
|||||||
@@ -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 {
|
if value == nil {
|
||||||
UserDefaults.standard.removeObject(forKey: preference.rawValue)
|
UserDefaults.standard.removeObject(forKey: preference.rawValue)
|
||||||
} else {
|
} else {
|
||||||
@@ -178,5 +178,9 @@ class Preferences {
|
|||||||
|
|
||||||
// Update the preferences cache in memory!
|
// Update the preferences cache in memory!
|
||||||
App.shared.container.preferences.cachedPreferences = Preferences.cache()
|
App.shared.container.preferences.cachedPreferences = Preferences.cache()
|
||||||
|
|
||||||
|
if notify {
|
||||||
|
NotificationCenter.default.post(name: Events.PreferencesUpdated, object: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ class CheckboxPreferenceBehavior: CheckboxPreferenceViewBehavior {
|
|||||||
self.preference = preference
|
self.preference = preference
|
||||||
self.button = button
|
self.button = button
|
||||||
self.button.state = Preferences.isEnabled(self.preference) ? .on : .off
|
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) {
|
public func toggled(checked: Bool) {
|
||||||
|
|||||||
@@ -73,9 +73,23 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
view.preference = preference
|
view.preference = preference
|
||||||
view.action = action
|
view.action = action
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
view, selector: #selector(view.refreshState),
|
||||||
|
name: Events.PreferencesUpdated, object: nil
|
||||||
|
)
|
||||||
|
|
||||||
return view
|
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) {
|
@IBAction func valueChanged(_ sender: Any) {
|
||||||
let index = self.popupButton.indexOfSelectedItem
|
let index = self.popupButton.indexOfSelectedItem
|
||||||
Preferences.update(self.preference, value: self.options[index].value)
|
Preferences.update(self.preference, value: self.options[index].value)
|
||||||
|
|||||||
@@ -954,8 +954,8 @@ PHP Monitor will tell Valet to unsecure and re-secure all expired domains for yo
|
|||||||
|
|
||||||
// THIRD-PARTY INTEGRATIONS
|
// THIRD-PARTY INTEGRATIONS
|
||||||
|
|
||||||
"alert.enable_integrations.title" = "An external application is trying to communicate with PHP Monitor";
|
"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" = "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.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. 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.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";
|
"alert.enable_integrations.ok" = "Allow Integrations";
|
||||||
"alert.enable_integrations.cancel" = "Don't Allow";
|
"alert.enable_integrations.cancel" = "Don't Allow";
|
||||||
|
|||||||
Reference in New Issue
Block a user