mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2026-03-29 16:10:08 +02:00
♻️ Reworked window management
- Now a language change does no longer require an app restart - Windows are managed via a WindowManager (alias for WindowCoordinator) - Removed obsolete and unused `timer` from App - Updated Japanese localization for label that was too long
This commit is contained in:
@@ -79,6 +79,10 @@
|
|||||||
035983A12E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
035983A12E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
||||||
035983A22E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
035983A22E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
||||||
035983A32E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
035983A32E97FA9100218DC7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329A9A02E92A2A800A62A12 /* Container.swift */; };
|
||||||
|
036061D72F4C705B00B5998F /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036061D62F4C705800B5998F /* WindowManager.swift */; };
|
||||||
|
036061D82F4C705B00B5998F /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036061D62F4C705800B5998F /* WindowManager.swift */; };
|
||||||
|
036061D92F4C705B00B5998F /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036061D62F4C705800B5998F /* WindowManager.swift */; };
|
||||||
|
036061DA2F4C705B00B5998F /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036061D62F4C705800B5998F /* WindowManager.swift */; };
|
||||||
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||||
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||||
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||||
@@ -1069,6 +1073,7 @@
|
|||||||
034515472EC4FB9800472561 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
|
034515472EC4FB9800472561 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
034515482EC4FBB500472561 /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/Localizable.strings; sourceTree = "<group>"; };
|
034515482EC4FBB500472561 /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
034515492EC4FBBD00472561 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
034515492EC4FBBD00472561 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
036061D62F4C705800B5998F /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = "<group>"; };
|
||||||
036C39012E5C883A008DAEDF /* Packagist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packagist.swift; sourceTree = "<group>"; };
|
036C39012E5C883A008DAEDF /* Packagist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packagist.swift; sourceTree = "<group>"; };
|
||||||
036C39072E5C88A2008DAEDF /* PackagistTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistTest.swift; sourceTree = "<group>"; };
|
036C39072E5C88A2008DAEDF /* PackagistTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistTest.swift; sourceTree = "<group>"; };
|
||||||
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistP2Response.swift; sourceTree = "<group>"; };
|
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistP2Response.swift; sourceTree = "<group>"; };
|
||||||
@@ -2242,6 +2247,7 @@
|
|||||||
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
||||||
C409349C298EE8E900D25014 /* AppUpdater.swift */,
|
C409349C298EE8E900D25014 /* AppUpdater.swift */,
|
||||||
03263A372E86D5E800BD0415 /* UpdateScheduler.swift */,
|
03263A372E86D5E800BD0415 /* UpdateScheduler.swift */,
|
||||||
|
036061D62F4C705800B5998F /* WindowManager.swift */,
|
||||||
);
|
);
|
||||||
path = App;
|
path = App;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2969,6 +2975,7 @@
|
|||||||
C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */,
|
C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */,
|
||||||
C417DC74277614690015E6EE /* Helpers.swift in Sources */,
|
C417DC74277614690015E6EE /* Helpers.swift in Sources */,
|
||||||
C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
|
C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
|
||||||
|
036061D92F4C705B00B5998F /* WindowManager.swift in Sources */,
|
||||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
||||||
03D846352EB64E39006EFE3C /* CrashReporter.swift in Sources */,
|
03D846352EB64E39006EFE3C /* CrashReporter.swift in Sources */,
|
||||||
C42759672627662800093CAE /* NSMenuExtension.swift in Sources */,
|
C42759672627662800093CAE /* NSMenuExtension.swift in Sources */,
|
||||||
@@ -3161,6 +3168,7 @@
|
|||||||
C4D3660D29113F20006BD146 /* System.swift in Sources */,
|
C4D3660D29113F20006BD146 /* System.swift in Sources */,
|
||||||
033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
|
033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
|
||||||
031D748B2F46307A00D4FF48 /* AddProxyView.swift in Sources */,
|
031D748B2F46307A00D4FF48 /* AddProxyView.swift in Sources */,
|
||||||
|
036061D72F4C705B00B5998F /* WindowManager.swift in Sources */,
|
||||||
C471E86D28F9BB650021E251 /* CustomPrefs.swift in Sources */,
|
C471E86D28F9BB650021E251 /* CustomPrefs.swift in Sources */,
|
||||||
C45D654E29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */,
|
C45D654E29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */,
|
||||||
C4E2E84C28FC1E70003B070C /* DataExtension.swift in Sources */,
|
C4E2E84C28FC1E70003B070C /* DataExtension.swift in Sources */,
|
||||||
@@ -3370,6 +3378,7 @@
|
|||||||
C4BF56AE2949381100379603 /* FakeValetInteractor.swift in Sources */,
|
C4BF56AE2949381100379603 /* FakeValetInteractor.swift in Sources */,
|
||||||
C471E8C228F9BB8F0021E251 /* DomainListVC+Actions.swift in Sources */,
|
C471E8C228F9BB8F0021E251 /* DomainListVC+Actions.swift in Sources */,
|
||||||
C4821C5D2C2DEDE200357A68 /* AppMenu.swift in Sources */,
|
C4821C5D2C2DEDE200357A68 /* AppMenu.swift in Sources */,
|
||||||
|
036061DA2F4C705B00B5998F /* WindowManager.swift in Sources */,
|
||||||
C45B91562956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
|
C45B91562956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
|
||||||
C471E8C628F9BB8F0021E251 /* PMTableView.swift in Sources */,
|
C471E8C628F9BB8F0021E251 /* PMTableView.swift in Sources */,
|
||||||
C471E8C728F9BB8F0021E251 /* Warning.swift in Sources */,
|
C471E8C728F9BB8F0021E251 /* Warning.swift in Sources */,
|
||||||
@@ -3640,6 +3649,7 @@
|
|||||||
C4AFC4B429C4F43300BF4E0D /* HomebrewUpgradableTest.swift in Sources */,
|
C4AFC4B429C4F43300BF4E0D /* HomebrewUpgradableTest.swift in Sources */,
|
||||||
037F441E2EDB9195002EBF75 /* ConfigWatchManager.swift in Sources */,
|
037F441E2EDB9195002EBF75 /* ConfigWatchManager.swift in Sources */,
|
||||||
C4E2E84828FC1D93003B070C /* TestableConfigurationTest.swift in Sources */,
|
C4E2E84828FC1D93003B070C /* TestableConfigurationTest.swift in Sources */,
|
||||||
|
036061D82F4C705B00B5998F /* WindowManager.swift in Sources */,
|
||||||
C4D936CB27E3EE4A00BD69FE /* DomainListCellProtocol.swift in Sources */,
|
C4D936CB27E3EE4A00BD69FE /* DomainListCellProtocol.swift in Sources */,
|
||||||
C4513F962B13E30C001AD760 /* BrewExtensionsObservable.swift in Sources */,
|
C4513F962B13E30C001AD760 /* BrewExtensionsObservable.swift in Sources */,
|
||||||
C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ Thank you very much for your contributions, kind words and support.
|
|||||||
|
|
||||||
### Loading info about PHP in the background
|
### Loading info about PHP in the background
|
||||||
|
|
||||||
This app runs `php-config --version` in the background periodically, usually whenever your Homebrew configuration is modified. A filesystem watcher is used to determine if anything changes in your Homebrew's `bin` directory.
|
This app runs `php-config --version` in the background, usually whenever your Homebrew configuration is modified. A filesystem watcher is used to determine if anything changes in your Homebrew's `bin` directory.
|
||||||
|
|
||||||
PHP Monitor also checks your `.ini` files for extensions and loads more information about your limits (memory limit, POST limit, upload limit). See also the section on *Config change detection* below.
|
PHP Monitor also checks your `.ini` files for extensions and loads more information about your limits (memory limit, POST limit, upload limit). See also the section on *Config change detection* below.
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,9 @@ class PhpEnvironments {
|
|||||||
// Update the synchronized value
|
// Update the synchronized value
|
||||||
_currentInstall.value = newValue
|
_currentInstall.value = newValue
|
||||||
// Let the PHP extension manager, if it exists, know the version changed
|
// Let the PHP extension manager, if it exists, know the version changed
|
||||||
App.shared.phpExtensionManagerWindowController?.view.didUpdatePhpVersion()
|
WindowManager
|
||||||
|
.controller(of: PhpExtensionManagerWC.self)?
|
||||||
|
.view.didUpdatePhpVersion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,4 +41,14 @@ extension App {
|
|||||||
NSApp.setActivationPolicy(!openWindows.isEmpty ? .regular : .accessory)
|
NSApp.setActivationPolicy(!openWindows.isEmpty ? .regular : .accessory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Closes and invalidates all cached secondary window controllers (excluding preferences).
|
||||||
|
This ensures that windows are recreated fresh, with the correct localization, the next
|
||||||
|
time they are opened. Each `close()` call triggers `windowWillClose`, which automatically
|
||||||
|
removes the window from `openWindows` via the existing delegate mechanism.
|
||||||
|
*/
|
||||||
|
public func invalidateCachedWindows() {
|
||||||
|
WindowManager.closeAll(excluding: [PreferencesWC.self])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,36 +81,12 @@ class App {
|
|||||||
*/
|
*/
|
||||||
var container: Container = Container()
|
var container: Container = Container()
|
||||||
|
|
||||||
/** The window controller of the currently active preferences window. */
|
|
||||||
var preferencesWindowController: PreferencesWindowController?
|
|
||||||
|
|
||||||
/** The window controller of the currently active site list window. */
|
|
||||||
var domainListWindowController: DomainListWindowController?
|
|
||||||
|
|
||||||
/** The window controller of the onboarding window. */
|
|
||||||
var onboardingWindowController: OnboardingWindowController?
|
|
||||||
|
|
||||||
/** The window controller of the config manager window. */
|
|
||||||
var phpConfigManagerWindowController: PhpConfigManagerWindowController?
|
|
||||||
|
|
||||||
/** The window controller of the warnings window. */
|
|
||||||
var phpDoctorWindowController: PhpDoctorWindowController?
|
|
||||||
|
|
||||||
/** The window controller of the PHP version manager window. */
|
|
||||||
var phpVersionManagerWindowController: PhpVersionManagerWindowController?
|
|
||||||
|
|
||||||
/** 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. */
|
/** URL that was received before the app finished booting. Will be processed once the startup procedure completes. */
|
||||||
var deferredURL: URL?
|
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] = []
|
||||||
|
|
||||||
/** Timer that will periodically reload info about the user's PHP installation. */
|
|
||||||
var timer: Timer?
|
|
||||||
|
|
||||||
// MARK: - Global Hotkey
|
// MARK: - Global Hotkey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +98,7 @@ class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Activation Policy
|
// MARK: - Windows and Activation Policy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Variable that keeps track of which windows are currently open.
|
Variable that keeps track of which windows are currently open.
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ extension AppDelegate {
|
|||||||
@IBAction func addSiteLinkPressed(_ sender: Any) {
|
@IBAction func addSiteLinkPressed(_ sender: Any) {
|
||||||
DomainListVC.show()
|
DomainListVC.show()
|
||||||
|
|
||||||
guard let windowController = App.shared.domainListWindowController else { return }
|
guard let windowController = WindowManager.controller(of: DomainListWC.self) else { return }
|
||||||
windowController.pressedAddLink(nil)
|
windowController.pressedAddLink(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func reloadDomainListPressed(_ sender: Any) {
|
@IBAction func reloadDomainListPressed(_ sender: Any) {
|
||||||
Task { // Reload domains
|
Task { // Reload domains
|
||||||
let vc = App.shared.domainListWindowController?
|
let vc = WindowManager
|
||||||
|
.controller(of: DomainListWC.self)?
|
||||||
.window?.contentViewController as? DomainListVC
|
.window?.contentViewController as? DomainListVC
|
||||||
|
|
||||||
if vc != nil {
|
if vc != nil {
|
||||||
@@ -50,7 +51,7 @@ extension AppDelegate {
|
|||||||
@IBAction func focusSearchField(_ sender: Any) {
|
@IBAction func focusSearchField(_ sender: Any) {
|
||||||
DomainListVC.show()
|
DomainListVC.show()
|
||||||
|
|
||||||
guard let windowController = App.shared.domainListWindowController else { return }
|
guard let windowController = WindowManager.controller(of: DomainListWC.self) else { return }
|
||||||
windowController.searchToolbarItem.searchField.becomeFirstResponder()
|
windowController.searchToolbarItem.searchField.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
73
phpmon/Domain/App/WindowManager.swift
Normal file
73
phpmon/Domain/App/WindowManager.swift
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// WindowCoordinator.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 23/02/2026.
|
||||||
|
// Copyright © 2026 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
typealias PreferencesWC = PreferencesWindowController
|
||||||
|
typealias DomainListWC = DomainListWindowController
|
||||||
|
typealias OnboardingWC = OnboardingWindowController
|
||||||
|
typealias PhpConfigManagerWC = PhpConfigManagerWindowController
|
||||||
|
typealias PhpDoctorWC = PhpDoctorWindowController
|
||||||
|
typealias PhpVersionManagerWC = PhpVersionManagerWindowController
|
||||||
|
typealias PhpExtensionManagerWC = PhpExtensionManagerWindowController
|
||||||
|
|
||||||
|
let WindowManager = WindowCoordinator.shared
|
||||||
|
|
||||||
|
final class WindowCoordinator {
|
||||||
|
static let shared = WindowCoordinator()
|
||||||
|
|
||||||
|
private var controllers: [ObjectIdentifier: NSWindowController] = [:]
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
func setController<T: NSWindowController>(_ controller: T) {
|
||||||
|
controllers[ObjectIdentifier(T.self)] = controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasController<T: NSWindowController>(for type: T.Type) -> Bool {
|
||||||
|
return controllers[ObjectIdentifier(T.self)] != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func controller<T: NSWindowController>(of type: T.Type) -> T? {
|
||||||
|
return controllers[ObjectIdentifier(T.self)] as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
func window<T: NSWindowController>(for type: T.Type) -> NSWindow? {
|
||||||
|
return controllers[ObjectIdentifier(T.self)]?.window
|
||||||
|
}
|
||||||
|
|
||||||
|
func withWindow<T: NSWindowController>(for type: T.Type, _ handler: (NSWindow) -> Void) {
|
||||||
|
guard let window = window(for: type) else { return }
|
||||||
|
handler(window)
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func show<T: NSWindowController>(_ type: T.Type) -> T? {
|
||||||
|
guard let controller = controller(of: type) else { return nil }
|
||||||
|
controller.showWindow(self)
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
controller.window?.orderFrontRegardless()
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func close<T: NSWindowController>(_ type: T.Type) {
|
||||||
|
controllers[ObjectIdentifier(T.self)]?.close()
|
||||||
|
controllers[ObjectIdentifier(T.self)] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeAll(excluding types: [NSWindowController.Type] = []) {
|
||||||
|
let excluded = Set(types.map { ObjectIdentifier($0) })
|
||||||
|
|
||||||
|
controllers.keys
|
||||||
|
.filter { !excluded.contains($0) }
|
||||||
|
.forEach { key in
|
||||||
|
controllers[key]?.close()
|
||||||
|
controllers[key] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,7 +117,7 @@ extension MainMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func reloadDomainListData() async {
|
private func reloadDomainListData() async {
|
||||||
if let window = App.shared.domainListWindowController {
|
if let window = WindowManager.controller(of: DomainListWC.self) {
|
||||||
await window.contentVC.reloadDomains()
|
await window.contentVC.reloadDomains()
|
||||||
} else {
|
} else {
|
||||||
await Valet.shared.reloadSites()
|
await Valet.shared.reloadSites()
|
||||||
|
|||||||
@@ -56,15 +56,11 @@ class GenericPreferenceVC: NSViewController {
|
|||||||
action: {
|
action: {
|
||||||
MainMenu.shared.refreshIcon()
|
MainMenu.shared.refreshIcon()
|
||||||
MainMenu.shared.rebuild()
|
MainMenu.shared.rebuild()
|
||||||
|
App.shared.invalidateCachedWindows()
|
||||||
|
|
||||||
if let window = App.shared.preferencesWindowController?.window {
|
// Re-open the preferences VC
|
||||||
let alert = NSAlert()
|
WindowManager.close(PreferencesWC.self)
|
||||||
alert.messageText = "alert.language_changed.title".localized
|
PreferencesWindowController.show()
|
||||||
alert.informativeText = "alert.language_changed.subtitle".localized
|
|
||||||
alert.alertStyle = .warning
|
|
||||||
alert.addButton(withTitle: "generic.ok".localized)
|
|
||||||
alert.beginSheetModal(for: window)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,19 +30,35 @@ class PreferencesWindowController: PMWindowController {
|
|||||||
window.delegate = delegate ?? windowController
|
window.delegate = delegate ?? windowController
|
||||||
window.styleMask = [.titled, .closable, .miniaturizable]
|
window.styleMask = [.titled, .closable, .miniaturizable]
|
||||||
|
|
||||||
App.shared.preferencesWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
var justCreated = false
|
var justCreated = false
|
||||||
|
|
||||||
if App.shared.preferencesWindowController == nil {
|
if !WindowManager.hasController(for: PreferencesWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
|
justCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
guard let preferencesWC = App.shared.preferencesWindowController else {
|
guard let preferencesWC = WindowManager.controller(of: PreferencesWC.self) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if justCreated {
|
||||||
|
addContentTabs(to: preferencesWC)
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowManager.show(PreferencesWC.self)
|
||||||
|
|
||||||
|
if justCreated {
|
||||||
|
preferencesWC.positionWindowInTopRightCorner()
|
||||||
|
}
|
||||||
|
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func addContentTabs(to preferencesWC: PreferencesWC) {
|
||||||
guard let tabVC = preferencesWC.contentViewController as? NSTabViewController else {
|
guard let tabVC = preferencesWC.contentViewController as? NSTabViewController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -58,19 +74,6 @@ class PreferencesWindowController: PMWindowController {
|
|||||||
width: tabVC.view.frame.size.width,
|
width: tabVC.view.frame.size.width,
|
||||||
height: tabVC.view.frame.size.height
|
height: tabVC.view.frame.size.height
|
||||||
)
|
)
|
||||||
|
|
||||||
justCreated = true
|
|
||||||
}
|
|
||||||
|
|
||||||
App.shared.preferencesWindowController?.showWindow(self)
|
|
||||||
|
|
||||||
if justCreated {
|
|
||||||
App.shared.preferencesWindowController?.positionWindowInTopRightCorner()
|
|
||||||
}
|
|
||||||
|
|
||||||
App.shared.preferencesWindowController?.window?.orderFrontRegardless()
|
|
||||||
|
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Tabs
|
// MARK: - Tabs
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ struct VersionPopoverView: View {
|
|||||||
LazyVGrid(columns: self.rows, alignment: .leading, spacing: 5, content: {
|
LazyVGrid(columns: self.rows, alignment: .leading, spacing: 5, content: {
|
||||||
ForEach(validPhpVersions, id: \.self) { version in
|
ForEach(validPhpVersions, id: \.self) { version in
|
||||||
Button("site_link.isolate_php".localized(version.short), action: {
|
Button("site_link.isolate_php".localized(version.short), action: {
|
||||||
App.shared.domainListWindowController?.contentVC
|
WindowManager.controller(of: DomainListWC.self)?.contentVC
|
||||||
.isolateSite(site: site, version: version.short)
|
.isolateSite(site: site, version: version.short)
|
||||||
parent?.close()
|
parent?.close()
|
||||||
}).padding(EdgeInsets(top: 3, leading: 0, bottom: 3, trailing: 0))
|
}).padding(EdgeInsets(top: 3, leading: 0, bottom: 3, trailing: 0))
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<key>LSUIElement</key>
|
<key>LSUIElement</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2019-2025 Nico Verbruggen. All rights reserved.</string>
|
<string>Copyright © 2019-2026 Nico Verbruggen. All rights reserved.</string>
|
||||||
<key>NSMainStoryboardFile</key>
|
<key>NSMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ class DomainListTLSCell: NSTableCellView, DomainListCellProtocol {
|
|||||||
tld: Valet.shared.config.tld,
|
tld: Valet.shared.config.tld,
|
||||||
expires: site.getListableCertificateExpiryDate(),
|
expires: site.getListableCertificateExpiryDate(),
|
||||||
callback: {
|
callback: {
|
||||||
App.shared.domainListWindowController?
|
WindowManager.controller(of: DomainListWC.self)?.contentVC
|
||||||
.contentVC.checkForCertificateRenewal()
|
.checkForCertificateRenewal()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ extension DomainListVC {
|
|||||||
}.joined(separator: "\n- ")
|
}.joined(separator: "\n- ")
|
||||||
|
|
||||||
// Ensure the window is accessible
|
// Ensure the window is accessible
|
||||||
guard let window = App.shared.domainListWindowController?.window else {
|
guard let window = WindowManager.window(for: DomainListWC.self) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,16 +27,14 @@ extension DomainListVC {
|
|||||||
window.minSize = NSSize(width: 550, height: 200)
|
window.minSize = NSSize(width: 550, height: 200)
|
||||||
window.setFrameAutosaveName("domainListWindow")
|
window.setFrameAutosaveName("domainListWindow")
|
||||||
|
|
||||||
App.shared.domainListWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.domainListWindowController == nil {
|
if !WindowManager.hasController(for: DomainListWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.domainListWindowController!.showWindow(self)
|
WindowManager.show(DomainListWC.self)
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
App.shared.domainListWindowController?.window?.orderFrontRegardless()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,8 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
icon: "globe",
|
icon: "globe",
|
||||||
button: "domain_list.domains_empty.button".localized,
|
button: "domain_list.domains_empty.button".localized,
|
||||||
action: {
|
action: {
|
||||||
App.shared.domainListWindowController?
|
WindowManager
|
||||||
|
.controller(of: DomainListWC.self)?
|
||||||
.pressedAddLink(nil)
|
.pressedAddLink(nil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ struct OnboardingView: View {
|
|||||||
.lineLimit(3)
|
.lineLimit(3)
|
||||||
.frame(height: 35)
|
.frame(height: 35)
|
||||||
Button("onboarding.tour.close".localized) {
|
Button("onboarding.tour.close".localized) {
|
||||||
App.shared.onboardingWindowController?.close()
|
WindowManager.close(OnboardingWC.self)
|
||||||
}
|
}
|
||||||
.padding(.bottom, 15)
|
.padding(.bottom, 15)
|
||||||
.padding(.top, 10)
|
.padding(.top, 10)
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ class OnboardingWindowController: PMWindowController {
|
|||||||
window.contentView = NSHostingView(rootView: OnboardingView())
|
window.contentView = NSHostingView(rootView: OnboardingView())
|
||||||
window.setContentSize(window.contentView!.fittingSize)
|
window.setContentSize(window.contentView!.fittingSize)
|
||||||
|
|
||||||
App.shared.onboardingWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.onboardingWindowController == nil {
|
if !WindowManager.hasController(for: OnboardingWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.onboardingWindowController?.showWindow(self)
|
WindowManager.show(OnboardingWC.self)
|
||||||
App.shared.onboardingWindowController?.window?.setCenterPosition(offsetY: 70)
|
WindowManager.withWindow(for: OnboardingWC.self) { window in
|
||||||
|
window.setCenterPosition(offsetY: 70)
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func close() {
|
override func close() {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ struct ConfigManagerView: View {
|
|||||||
|
|
||||||
VStack(alignment: .trailing) {
|
VStack(alignment: .trailing) {
|
||||||
Button("Close", action: {
|
Button("Close", action: {
|
||||||
App.shared.phpConfigManagerWindowController?.close()
|
WindowManager.close(PhpConfigManagerWC.self)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
|
|||||||
@@ -29,18 +29,16 @@ class PhpConfigManagerWindowController: PMWindowController {
|
|||||||
window.contentView = NSHostingView(rootView: ConfigManagerView())
|
window.contentView = NSHostingView(rootView: ConfigManagerView())
|
||||||
window.setContentSize(NSSize(width: 600, height: 480))
|
window.setContentSize(NSSize(width: 600, height: 480))
|
||||||
|
|
||||||
App.shared.phpConfigManagerWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.phpConfigManagerWindowController == nil {
|
if !WindowManager.hasController(for: PhpConfigManagerWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.phpConfigManagerWindowController?.showWindow(self)
|
WindowManager.show(PhpConfigManagerWC.self)
|
||||||
App.shared.phpConfigManagerWindowController?.positionWindowInTopRightCorner()
|
WindowManager.controller(of: PhpConfigManagerWC.self)?
|
||||||
|
.positionWindowInTopRightCorner()
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
App.shared.phpConfigManagerWindowController?.window?.orderFrontRegardless()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,8 @@ extension WarningManager {
|
|||||||
fix: {
|
fix: {
|
||||||
await DomainListVC.show()
|
await DomainListVC.show()
|
||||||
|
|
||||||
if let vc = await App.shared.domainListWindowController?
|
if let vc = await WindowManager
|
||||||
|
.controller(of: DomainListWC.self)?
|
||||||
.window?.contentViewController as? DomainListVC {
|
.window?.contentViewController as? DomainListVC {
|
||||||
await vc.checkForCertificateRenewal {
|
await vc.checkForCertificateRenewal {
|
||||||
await self.checkEnvironment()
|
await self.checkEnvironment()
|
||||||
|
|||||||
@@ -29,18 +29,17 @@ class PhpDoctorWindowController: PMWindowController {
|
|||||||
window.contentView = NSHostingView(rootView: PhpDoctorView())
|
window.contentView = NSHostingView(rootView: PhpDoctorView())
|
||||||
window.setContentSize(window.contentView!.fittingSize)
|
window.setContentSize(window.contentView!.fittingSize)
|
||||||
|
|
||||||
App.shared.phpDoctorWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.phpDoctorWindowController == nil {
|
if !WindowManager.hasController(for: PhpDoctorWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.phpDoctorWindowController?.showWindow(self)
|
WindowManager.show(PhpDoctorWC.self)
|
||||||
App.shared.phpDoctorWindowController?.window?.setCenterPosition(offsetY: 70)
|
WindowManager.withWindow(for: PhpDoctorWC.self) { window in
|
||||||
|
window.setCenterPosition(offsetY: 70)
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
}
|
||||||
App.shared.phpDoctorWindowController?.window?.orderFrontRegardless()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ extension PhpExtensionManagerView {
|
|||||||
button: String,
|
button: String,
|
||||||
style: NSAlert.Style = .critical
|
style: NSAlert.Style = .critical
|
||||||
) {
|
) {
|
||||||
|
WindowManager.withWindow(for: PhpExtensionManagerWC.self) { window in
|
||||||
Alert.confirm(
|
Alert.confirm(
|
||||||
onWindow: App.shared.phpExtensionManagerWindowController!.window!,
|
onWindow: window,
|
||||||
messageText: title,
|
messageText: title,
|
||||||
informativeText: description,
|
informativeText: description,
|
||||||
buttonTitle: button,
|
buttonTitle: button,
|
||||||
@@ -26,6 +27,7 @@ extension PhpExtensionManagerView {
|
|||||||
onFirstButtonPressed: {}
|
onFirstButtonPressed: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func install(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
|
public func install(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
|
||||||
Task {
|
Task {
|
||||||
@@ -35,8 +37,9 @@ extension PhpExtensionManagerView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func confirmUninstall(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
|
public func confirmUninstall(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
|
||||||
|
WindowManager.withWindow(for: PhpExtensionManagerWC.self) { window in
|
||||||
Alert.confirm(
|
Alert.confirm(
|
||||||
onWindow: App.shared.phpExtensionManagerWindowController!.window!,
|
onWindow: window,
|
||||||
messageText: "phpextman.warnings.removal.title".localized(ext.name),
|
messageText: "phpextman.warnings.removal.title".localized(ext.name),
|
||||||
informativeText: "phpextman.warnings.removal.desc".localized(ext.name),
|
informativeText: "phpextman.warnings.removal.desc".localized(ext.name),
|
||||||
buttonTitle: "phpextman.warnings.removal.button".localized,
|
buttonTitle: "phpextman.warnings.removal.button".localized,
|
||||||
@@ -51,6 +54,7 @@ extension PhpExtensionManagerView {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func runCommand(_ command: BrewCommand) async {
|
public func runCommand(_ command: BrewCommand) async {
|
||||||
if App.shared.container.phpEnvs.isBusy {
|
if App.shared.container.phpEnvs.isBusy {
|
||||||
|
|||||||
@@ -34,19 +34,16 @@ class PhpExtensionManagerWindowController: PMWindowController {
|
|||||||
window.contentView = NSHostingView(rootView: windowController.view)
|
window.contentView = NSHostingView(rootView: windowController.view)
|
||||||
window.setContentSize(NSSize(width: 600, height: 800))
|
window.setContentSize(NSSize(width: 600, height: 800))
|
||||||
|
|
||||||
App.shared.phpExtensionManagerWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.phpExtensionManagerWindowController == nil {
|
if !WindowManager.hasController(for: PhpExtensionManagerWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.phpExtensionManagerWindowController?.showWindow(self)
|
WindowManager.show(PhpExtensionManagerWC.self)
|
||||||
App.shared.phpExtensionManagerWindowController?.positionWindowInTopRightCorner()
|
WindowManager.controller(of: PhpExtensionManagerWC.self)?
|
||||||
|
.positionWindowInTopRightCorner()
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
|
|
||||||
App.shared.phpExtensionManagerWindowController?.window?.orderFrontRegardless()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,8 +153,9 @@ extension PhpVersionManagerView {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WindowManager.withWindow(for: PhpVersionManagerWC.self) { window in
|
||||||
Alert.confirm(
|
Alert.confirm(
|
||||||
onWindow: App.shared.phpVersionManagerWindowController!.window!,
|
onWindow: window,
|
||||||
messageText: "phpman.warnings.removal.title".localized(formula.displayName),
|
messageText: "phpman.warnings.removal.title".localized(formula.displayName),
|
||||||
informativeText: "phpman.warnings.removal.desc".localized(formula.displayName),
|
informativeText: "phpman.warnings.removal.desc".localized(formula.displayName),
|
||||||
buttonTitle: "phpman.warnings.removal.button".localized,
|
buttonTitle: "phpman.warnings.removal.button".localized,
|
||||||
@@ -166,6 +167,7 @@ extension PhpVersionManagerView {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Present a generic error alert attached to the window.
|
Present a generic error alert attached to the window.
|
||||||
@@ -176,8 +178,9 @@ extension PhpVersionManagerView {
|
|||||||
button: String,
|
button: String,
|
||||||
style: NSAlert.Style = .critical
|
style: NSAlert.Style = .critical
|
||||||
) {
|
) {
|
||||||
|
WindowManager.withWindow(for: PhpVersionManagerWC.self) { window in
|
||||||
Alert.confirm(
|
Alert.confirm(
|
||||||
onWindow: App.shared.phpVersionManagerWindowController!.window!,
|
onWindow: window,
|
||||||
messageText: title,
|
messageText: title,
|
||||||
informativeText: description,
|
informativeText: description,
|
||||||
buttonTitle: button,
|
buttonTitle: button,
|
||||||
@@ -186,5 +189,6 @@ extension PhpVersionManagerView {
|
|||||||
onFirstButtonPressed: {}
|
onFirstButtonPressed: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,19 +36,16 @@ class PhpVersionManagerWindowController: PMWindowController {
|
|||||||
window.contentView = NSHostingView(rootView: windowController.view)
|
window.contentView = NSHostingView(rootView: windowController.view)
|
||||||
window.setContentSize(NSSize(width: 600, height: 800))
|
window.setContentSize(NSSize(width: 600, height: 800))
|
||||||
|
|
||||||
App.shared.phpVersionManagerWindowController = windowController
|
WindowManager.setController(windowController)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if App.shared.phpVersionManagerWindowController == nil {
|
if !WindowManager.hasController(for: PhpVersionManagerWC.self) {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.phpVersionManagerWindowController?.showWindow(self)
|
WindowManager.show(PhpVersionManagerWC.self)
|
||||||
App.shared.phpVersionManagerWindowController?.positionWindowInTopRightCorner()
|
WindowManager.controller(of: PhpVersionManagerWC.self)?
|
||||||
|
.positionWindowInTopRightCorner()
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
|
|
||||||
App.shared.phpVersionManagerWindowController?.window?.orderFrontRegardless()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,7 +265,7 @@
|
|||||||
"prefs.tabs.appearance" = "外観";
|
"prefs.tabs.appearance" = "外観";
|
||||||
"prefs.tabs.visibility" = "可視性";
|
"prefs.tabs.visibility" = "可視性";
|
||||||
"prefs.tabs.notifications" = "通知";
|
"prefs.tabs.notifications" = "通知";
|
||||||
"prefs.global_shortcut" = "グローバルショートカット:";
|
"prefs.global_shortcut" = "グローバルキー:";
|
||||||
"prefs.dynamic_icon" = "アイコンタイプ:";
|
"prefs.dynamic_icon" = "アイコンタイプ:";
|
||||||
"prefs.info_density" = "情報密度:";
|
"prefs.info_density" = "情報密度:";
|
||||||
"prefs.services" = "サービス:";
|
"prefs.services" = "サービス:";
|
||||||
|
|||||||
Reference in New Issue
Block a user