diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index f95f207..49f2077 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -131,6 +131,8 @@ C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; }; C42759672627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; }; C42759682627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; }; + C4292D542B023F61004F0D2A /* PhpExtensionManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */; }; + C4292D562B024006004F0D2A /* PhpExtensionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */; }; C4297F7A28970D59004C4630 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; }; C42C49DB27C2806F0074ABAC /* MainMenu+FixMyValet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */; }; C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; }; @@ -940,6 +942,8 @@ C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; C42337A2281F19F000459A48 /* Xdebug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Xdebug.swift; sourceTree = ""; }; C42759662627662800093CAE /* NSMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuExtension.swift; sourceTree = ""; }; + C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtensionManagerWindowController.swift; sourceTree = ""; }; + C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtensionManagerView.swift; sourceTree = ""; }; C4297F7928970D59004C4630 /* WarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WarningView.swift; sourceTree = ""; }; C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+FixMyValet.swift"; sourceTree = ""; }; C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = ""; }; @@ -1417,6 +1421,23 @@ path = Extensions; sourceTree = ""; }; + C4292D512B023F37004F0D2A /* PHP Extension Manager */ = { + isa = PBXGroup; + children = ( + C4292D522B023F52004F0D2A /* UI */, + ); + path = "PHP Extension Manager"; + sourceTree = ""; + }; + C4292D522B023F52004F0D2A /* UI */ = { + isa = PBXGroup; + children = ( + C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */, + C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */, + ); + path = UI; + sourceTree = ""; + }; C4297F7828970D4E004C4630 /* PHP Doctor */ = { isa = PBXGroup; children = ( @@ -1552,6 +1573,7 @@ C44DFA7A2A6703FD00B98ED5 /* PHP Config Editor */, C4297F7828970D4E004C4630 /* PHP Doctor */, C43931C329C4BD510069165B /* PHP Version Manager */, + C4292D512B023F37004F0D2A /* PHP Extension Manager */, ); path = Modules; sourceTree = ""; @@ -2410,12 +2432,14 @@ C4B79EC629CA474200A483EE /* FakeCommand.swift in Sources */, C4ACA38F25C754C100060C66 /* PhpExtension.swift in Sources */, C47DF1AF299D5A3B0007055D /* LoginItemManager.swift in Sources */, + C4292D542B023F61004F0D2A /* PhpExtensionManagerWindowController.swift in Sources */, C4D3661A291173EA006BD146 /* DictionaryExtension.swift in Sources */, C4C8900728F0E3EF00CE5E97 /* ActiveFileSystem.swift in Sources */, C409349D298EE8E900D25014 /* AppUpdater.swift in Sources */, C4D8016622B1584700C6DA1B /* Startup.swift in Sources */, C43931CA29C4C03F0069165B /* Brew.swift in Sources */, C42C49DB27C2806F0074ABAC /* MainMenu+FixMyValet.swift in Sources */, + C4292D562B024006004F0D2A /* PhpExtensionManagerView.swift in Sources */, C48D6C70279CD2AC00F26D7E /* VersionNumber.swift in Sources */, C4998F0A2617633900B2526E /* PreferencesWindowController.swift in Sources */, C46FA9882822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */, diff --git a/phpmon/Common/Core/Actions.swift b/phpmon/Common/Core/Actions.swift index b62bdf8..8a5b5b1 100644 --- a/phpmon/Common/Core/Actions.swift +++ b/phpmon/Common/Core/Actions.swift @@ -14,8 +14,6 @@ class Actions { public static func linkPhp() async { await brew("link php --overwrite --force") - - // TODO: Verify that this worked, if not, notify the user } public static func restartPhpFpm() async { diff --git a/phpmon/Domain/App/App.swift b/phpmon/Domain/App/App.swift index 52bff0d..8d6e522 100644 --- a/phpmon/Domain/App/App.swift +++ b/phpmon/Domain/App/App.swift @@ -83,6 +83,9 @@ class App { /** The window controller of the PHP version manager window. */ var phpVersionManagerWindowController: PhpVersionManagerWindowController? + /** The window controller of the PHP extension manager window. */ + var phpExtensionManagerWindowController: PhpExtensionManagerWindowController? + /** List of detected (installed) applications that PHP Monitor can work with. */ var detectedApplications: [Application] = [] diff --git a/phpmon/Domain/Menu/MainMenu+Startup.swift b/phpmon/Domain/Menu/MainMenu+Startup.swift index 654b3e4..3cd2bb7 100644 --- a/phpmon/Domain/Menu/MainMenu+Startup.swift +++ b/phpmon/Domain/Menu/MainMenu+Startup.swift @@ -128,10 +128,6 @@ extension MainMenu { // Check if the linked version has changed between launches of phpmon PhpGuard().compareToLastGlobalVersion() - #warning("Move to a dedicated module and check if tap is installed first!") - // let extensions = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")["8.2"]! - // print("The following extensions can be installed for this version of PHP: \(extensions)") - // We are ready! Log.info("PHP Monitor is ready to serve!") diff --git a/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerView.swift b/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerView.swift new file mode 100644 index 0000000..6fac457 --- /dev/null +++ b/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerView.swift @@ -0,0 +1,103 @@ +// +// PhpExtensionManagerView.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 13/11/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation +import SwiftUI + +// Temp model for UI purposes +struct BrewPhpExtension { + let name: String + let isInstalled: Bool +} + +struct PhpExtensionManagerView: View { + init() { + let available = BrewTapFormulae + .from(tap: "shivammathur/homebrew-extensions")["8.2"]!.sorted() + + print(available) + + let extensions = available.map({ name in + return BrewPhpExtension(name: name, isInstalled: false) + }) + + self.extensions = extensions + } + + @State var searchText: String = "" + @State var extensions: [BrewPhpExtension] + + var body: some View { + VStack { + header.padding(20) + + List(Array(extensions.enumerated()), id: \.1.name) { (index, pExtension) in + listContent(for: pExtension) + .listRowBackground( + index % 2 == 0 + ? Color.gray.opacity(0) + : Color.gray.opacity(0.08) + ) + .padding(.vertical, 8) + .padding(.horizontal, 8) + } + .edgesIgnoringSafeArea(.top) + .listStyle(PlainListStyle()) + .searchable(text: $searchText) + }.frame(width: 600, height: 600) + } + + // MARK: View Variables + + private var header: some View { + HStack(alignment: .center, spacing: 15) { + Image(systemName: "puzzlepiece.extension.fill") + .resizable() + .frame(width: 40, height: 40) + .foregroundColor(Color.blue) + .padding(12) + VStack(alignment: .leading, spacing: 5) { + Text("phpextman.description".localizedForSwiftUI) + .font(.system(size: 12)) + .frame(maxWidth: .infinity, alignment: .leading) + Text("phpextman.disclaimer".localizedForSwiftUI) + .font(.system(size: 12)) + .foregroundColor(.gray) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + } + + private func listContent(for bExtension: BrewPhpExtension) -> some View { + HStack(alignment: .center, spacing: 7.0) { + VStack(alignment: .leading, spacing: 0) { + HStack { + Text(bExtension.name).bold() + } + } + .frame(maxWidth: .infinity, alignment: .leading) + + HStack { + if bExtension.isInstalled { + Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) { + + } + } else { + Button("phpman.buttons.install".localizedForSwiftUI) { + + } + } + } + } + } +} + +#Preview { + PhpExtensionManagerView() + .frame(width: 600, height: 600) +} diff --git a/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerWindowController.swift b/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerWindowController.swift new file mode 100644 index 0000000..c76aaca --- /dev/null +++ b/phpmon/Modules/PHP Extension Manager/UI/PhpExtensionManagerWindowController.swift @@ -0,0 +1,55 @@ +// +// PhpVersionManagerWindowController.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 13/11/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation +import Cocoa +import SwiftUI + +class PhpExtensionManagerWindowController: PMWindowController { + + // MARK: - Window Identifier + + var view: PhpVersionManagerView! + + override var windowName: String { + return "PhpExtensionManager" + } + + public static func create(delegate: NSWindowDelegate?) { + let windowController = Self() + + windowController.window = NSWindow() + windowController.view = PhpVersionManagerView( + formulae: Brew.shared.formulae, + handler: BrewPhpFormulaeHandler() + ) + + guard let window = windowController.window else { return } + window.title = "" + window.styleMask = [.titled, .closable, .miniaturizable] + window.titlebarAppearsTransparent = true + window.delegate = delegate ?? windowController + window.contentView = NSHostingView(rootView: windowController.view) + window.setContentSize(NSSize(width: 600, height: 800)) + + App.shared.phpExtensionManagerWindowController = windowController + } + + public static func show(delegate: NSWindowDelegate? = nil) { + if App.shared.phpExtensionManagerWindowController == nil { + Self.create(delegate: delegate) + } + + App.shared.phpExtensionManagerWindowController?.showWindow(self) + App.shared.phpExtensionManagerWindowController?.positionWindowInTopRightCorner() + + NSApp.activate(ignoringOtherApps: true) + + App.shared.phpExtensionManagerWindowController?.window?.orderFrontRegardless() + } +} diff --git a/phpmon/en.lproj/Localizable.strings b/phpmon/en.lproj/Localizable.strings index bd5c8dd..fe1d268 100644 --- a/phpmon/en.lproj/Localizable.strings +++ b/phpmon/en.lproj/Localizable.strings @@ -98,6 +98,11 @@ "php_ini.upload_max_filesize.title" = "Upload Max Size"; "php_ini.upload_max_filesize.description" = "The maximum size of an uploaded file. POST Max Size must be larger than this value."; +// PHPEXTMAN + +"phpextman.description" = "**PHP Extension Manager** lets you manage different PHP extensions with a simple click of the button. Because Homebrew is used, extensions won't need to be compiled on the fly using `pecl`."; +"phpextman.disclaimer" = "Certain extensions may require other dependencies to be installed, but generally speaking installing extensions should be much faster than installing PHP versions."; + // PHPMAN "phpman.busy.title" = "Checking for updates!";