1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-11-06 04:40:07 +01:00

⬆️ Adopt #Preview, cleanup PHP Version Manager

This commit is contained in:
2023-11-07 17:56:38 +01:00
parent 9a3dd2fa22
commit a634d083a6
18 changed files with 465 additions and 411 deletions

View File

@@ -122,6 +122,10 @@
C41F3D08298AED0D0042ACBF /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660A29113F20006BD146 /* System.swift */; }; C41F3D08298AED0D0042ACBF /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660A29113F20006BD146 /* System.swift */; };
C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; }; C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; };
C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; }; C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; };
C42106662AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */; };
C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */; };
C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */; };
C42106692AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */; };
C422DDAA28A2C49900CEAC97 /* PhpDoctorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C422DDA928A2C49900CEAC97 /* PhpDoctorView.swift */; }; C422DDAA28A2C49900CEAC97 /* PhpDoctorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C422DDA928A2C49900CEAC97 /* PhpDoctorView.swift */; };
C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; }; C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; };
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; }; C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; };
@@ -938,6 +942,7 @@
C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = "<group>"; }; C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = "<group>"; };
C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+ContextMenu.swift"; sourceTree = "<group>"; }; C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+ContextMenu.swift"; sourceTree = "<group>"; };
C4205A7D27F4D21800191A39 /* ValetProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxy.swift; sourceTree = "<group>"; }; C4205A7D27F4D21800191A39 /* ValetProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxy.swift; sourceTree = "<group>"; };
C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhpVersionManagerView+Actions.swift"; sourceTree = "<group>"; };
C422DDA928A2C49900CEAC97 /* PhpDoctorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpDoctorView.swift; sourceTree = "<group>"; }; C422DDA928A2C49900CEAC97 /* PhpDoctorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpDoctorView.swift; sourceTree = "<group>"; };
C422DDAC28A2DAC600CEAC97 /* PhpDoctorWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpDoctorWindowController.swift; sourceTree = "<group>"; }; C422DDAC28A2DAC600CEAC97 /* PhpDoctorWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpDoctorWindowController.swift; sourceTree = "<group>"; };
C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = "<group>"; }; C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = "<group>"; };
@@ -1494,6 +1499,7 @@
children = ( children = (
C4D5576329C77CC5001A44CD /* PhpVersionManagerWindowController.swift */, C4D5576329C77CC5001A44CD /* PhpVersionManagerWindowController.swift */,
C43931C429C4BD610069165B /* PhpVersionManagerView.swift */, C43931C429C4BD610069165B /* PhpVersionManagerView.swift */,
C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */,
C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */, C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */,
); );
path = UI; path = UI;
@@ -2586,6 +2592,7 @@
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */, C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */,
54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */, 54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
C42106662AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */, C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */,
C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */, C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
@@ -2775,6 +2782,7 @@
C471E81428F9BAE80021E251 /* NSWindowExtension.swift in Sources */, C471E81428F9BAE80021E251 /* NSWindowExtension.swift in Sources */,
C43BCD4629FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */, C43BCD4629FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */,
C471E7D328F9BA8F0021E251 /* ActiveShell.swift in Sources */, C471E7D328F9BA8F0021E251 /* ActiveShell.swift in Sources */,
C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */, C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */,
C471E7DE28F9BAA30021E251 /* CommandProtocol.swift in Sources */, C471E7DE28F9BAA30021E251 /* CommandProtocol.swift in Sources */,
C471E81B28F9BB250021E251 /* BetterAlertVC.swift in Sources */, C471E81B28F9BB250021E251 /* BetterAlertVC.swift in Sources */,
@@ -2831,6 +2839,7 @@
C471E89F28F9BB8F0021E251 /* ValetDomainScanner.swift in Sources */, C471E89F28F9BB8F0021E251 /* ValetDomainScanner.swift in Sources */,
C471E8A028F9BB8F0021E251 /* FakeDomainScanner.swift in Sources */, C471E8A028F9BB8F0021E251 /* FakeDomainScanner.swift in Sources */,
C471E8A228F9BB8F0021E251 /* AppDelegate.swift in Sources */, C471E8A228F9BB8F0021E251 /* AppDelegate.swift in Sources */,
C42106692AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C43931CD29C4C03F0069165B /* Brew.swift in Sources */, C43931CD29C4C03F0069165B /* Brew.swift in Sources */,
C451AFF92969E40F0078E617 /* HelpButton.swift in Sources */, C451AFF92969E40F0078E617 /* HelpButton.swift in Sources */,
C4ACE9E429F84EDD00110766 /* PhpGuard.swift in Sources */, C4ACE9E429F84EDD00110766 /* PhpGuard.swift in Sources */,
@@ -3083,6 +3092,7 @@
C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */, C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */, C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */,
C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */, C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */,
C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */, C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */,
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */, 54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */,

View File

@@ -27,15 +27,15 @@ struct HelpButton: View {
.buttonStyle(BorderlessButtonStyle()) .buttonStyle(BorderlessButtonStyle())
.focusable(false) .focusable(false)
} }
}
struct HelpButton_Previews: PreviewProvider {
static var previews: some View { #Preview("Light Mode") {
Group { HelpButton(action: {})
HelpButton(action: {}).padding() .padding(100)
.previewDisplayName("Light Mode") }
HelpButton(action: {}).padding().preferredColorScheme(.dark)
.previewDisplayName("Dark Mode") #Preview("Dark Mode") {
} HelpButton(action: {})
} .padding(100)
} .preferredColorScheme(.dark)
} }

View File

@@ -30,8 +30,6 @@ struct NoDomainResults: View {
} }
} }
struct NoDomainResults_Previews: PreviewProvider { #Preview {
static var previews: some View { NoDomainResults()
NoDomainResults()
}
} }

View File

@@ -126,78 +126,82 @@ struct DisclaimerView: View {
} }
} }
struct VersionPopoverView_Previews: PreviewProvider { #Preview("Unknown Requirement") {
static var previews: some View { VersionPopoverView(
VersionPopoverView( site: FakeValetSite(
site: FakeValetSite( fakeWithName: "amazingwebsite",
fakeWithName: "amazingwebsite", tld: "test",
tld: "test", secure: true,
secure: true, path: "/path/to/site",
path: "/path/to/site", linked: true,
linked: true, constraint: ""
constraint: "" ),
), validPhpVersions: [],
validPhpVersions: [], parent: nil
parent: nil )
) }
.previewDisplayName("Unknown Requirement")
#Preview("Requirement Matches") {
VersionPopoverView( VersionPopoverView(
site: FakeValetSite( site: FakeValetSite(
fakeWithName: "amazingwebsite", fakeWithName: "amazingwebsite",
tld: "test", tld: "test",
secure: true, secure: true,
path: "/path/to/site", path: "/path/to/site",
linked: true, linked: true,
constraint: "^8.1" constraint: "^8.1"
), ),
validPhpVersions: [], validPhpVersions: [],
parent: nil parent: nil
) )
.previewDisplayName("Requirement Matches") }
VersionPopoverView(
site: FakeValetSite( #Preview("Isolated") {
fakeWithName: "anothersite", VersionPopoverView(
tld: "test", site: FakeValetSite(
secure: true, fakeWithName: "anothersite",
path: "/path/to/site", tld: "test",
linked: true, secure: true,
constraint: "^8.0", path: "/path/to/site",
isolated: "8.0" linked: true,
), constraint: "^8.0",
validPhpVersions: [], isolated: "8.0"
parent: nil ),
) validPhpVersions: [],
.previewDisplayName("Isolated") parent: nil
VersionPopoverView( )
site: FakeValetSite( }
fakeWithName: "anothersite",
tld: "test", #Preview("Isolated Mismatch") {
secure: true, VersionPopoverView(
path: "/path/to/site", site: FakeValetSite(
linked: true, fakeWithName: "anothersite",
constraint: "^8.0", tld: "test",
isolated: "7.4" secure: true,
), path: "/path/to/site",
validPhpVersions: [], linked: true,
parent: nil constraint: "^8.0",
) isolated: "7.4"
.previewDisplayName("Isolated Mismatch") ),
VersionPopoverView( validPhpVersions: [],
site: FakeValetSite( parent: nil
fakeWithName: "anothersite", )
tld: "test", }
secure: true,
path: "/path/to/site", #Preview("Recommend Alternatives") {
linked: true, VersionPopoverView(
constraint: "^8.0" site: FakeValetSite(
), fakeWithName: "anothersite",
validPhpVersions: [ tld: "test",
VersionNumber(major: 8, minor: 0, patch: 0), secure: true,
VersionNumber(major: 8, minor: 1, patch: 0) path: "/path/to/site",
], linked: true,
parent: nil constraint: "^8.0"
) ),
.previewDisplayName("Recommend Alternatives") validPhpVersions: [
} VersionNumber(major: 8, minor: 0, patch: 0),
VersionNumber(major: 8, minor: 1, patch: 0)
],
parent: nil
)
} }

View File

@@ -45,9 +45,7 @@ struct HeaderView: View {
} }
} }
struct HeaderView_Previews: PreviewProvider { #Preview {
static var previews: some View { HeaderView(text: "Hello world")
HeaderView(text: "Hello world") .frame(width: 330.0)
.frame(width: 330.0)
}
} }

View File

@@ -172,23 +172,21 @@ struct ServiceView: View {
} }
} }
struct ServicesView_Previews: PreviewProvider { #Preview("Active 1") {
static var previews: some View { ServicesView(manager: FakeServicesManager(
ServicesView(manager: FakeServicesManager( formulae: ["php", "nginx", "dnsmasq"],
formulae: ["php", "nginx", "dnsmasq"], status: .active
status: .active ), perRow: 4)
), perRow: 4) .frame(width: 330.0)
.frame(width: 330.0) }
.previewDisplayName("Active 1")
#Preview("Active 2") {
ServicesView(manager: FakeServicesManager( ServicesView(manager: FakeServicesManager(
formulae: [ formulae: [
"php", "nginx", "dnsmasq", "thing1", "php", "nginx", "dnsmasq", "thing1",
"thing2", "thing3", "thing4", "thing5" "thing2", "thing3", "thing4", "thing5"
], ],
status: .inactive status: .inactive
), perRow: 4) ), perRow: 4)
.frame(width: 330.0) .frame(width: 330.0)
.previewDisplayName("Active 2")
}
} }

View File

@@ -98,12 +98,10 @@ struct StatsView: View {
} }
} }
struct StatsView_Previews: PreviewProvider { #Preview {
static var previews: some View { StatsView(
StatsView( memoryLimit: "1024 MB",
memoryLimit: "1024 MB", maxPostSize: "1024 MB",
maxPostSize: "1024 MB", maxUploadSize: "1024 MB"
maxUploadSize: "1024 MB" ).frame(height: 100)
).frame(height: 100)
}
} }

View File

@@ -53,13 +53,11 @@ struct ProgressWindowView: View {
} }
} }
struct ProgressWindowView_Previews: PreviewProvider { #Preview {
static var previews: some View { ProgressWindowView(
ProgressWindowView( subject: ProgressViewSubject(
subject: ProgressViewSubject( title: "Long running task",
title: "Long running task", description: "Please be patient"
description: "Please be patient"
)
) )
} )
} }

View File

@@ -136,10 +136,6 @@ struct OnboardingView: View {
} }
} }
struct OnboardingView_Previews: PreviewProvider { #Preview {
static var previews: some View { OnboardingView()
Group {
OnboardingView()
}
}
} }

View File

@@ -98,19 +98,19 @@ struct ByteLimitView: View {
} }
} }
struct ByteLimitView_Previews: PreviewProvider { #Preview("Byte Limit View") {
static var previews: some View { PreferenceContainer(
PreferenceContainer( name: "Max Size",
name: "Max Size", description:
description: "Here's an extensive description that is obviously way too long but it should wrap." +
"Here's an extensive description that is obviously way too long but it should wrap." + "The point of the wrapping text is that is allows us to see what's going on with the layout here."
"The point of the wrapping text is that is allows us to see what's going on with the layout here." ) {
) { ByteLimitView(preference: BytePhpPreference(key: "max_memory"))
ByteLimitView(preference: BytePhpPreference(key: "max_memory")) }.frame(width: 600, height: 200)
}.frame(width: 600, height: 200) }
ConfigManagerView() #Preview("Config Manager") {
.frame(width: 600, height: .infinity) ConfigManagerView()
.previewDisplayName("Config Manager") .frame(width: 600, height: .infinity)
} .previewDisplayName("Config Manager")
} }

View File

@@ -84,10 +84,6 @@ struct ConfigManagerView: View {
} }
} }
struct ConfigManagerView_Previews: PreviewProvider { #Preview {
static var previews: some View { ConfigManagerView().frame(width: 600)
ConfigManagerView()
.frame(width: 600)
.previewDisplayName("Live Preview")
}
} }

View File

@@ -34,8 +34,8 @@ class WarningManager: ObservableObject {
.trimmingCharacters(in: .whitespacesAndNewlines) == "1" .trimmingCharacters(in: .whitespacesAndNewlines) == "1"
}, },
name: "Running PHP Monitor with Rosetta on M1", name: "Running PHP Monitor with Rosetta on M1",
title: "warnings.arm_compatibility.title".localized, title: "warnings.arm_compatibility.title",
paragraphs: { return ["warnings.arm_compatibility.description".localized] }, paragraphs: { return ["warnings.arm_compatibility.description"] },
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon" url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon"
), ),
Warning( Warning(
@@ -44,11 +44,11 @@ class WarningManager: ObservableObject {
!FileSystem.isWriteableFile("/usr/local/bin/") !FileSystem.isWriteableFile("/usr/local/bin/")
}, },
name: "Helpers cannot be symlinked and not in PATH", name: "Helpers cannot be symlinked and not in PATH",
title: "warnings.helper_permissions.title".localized, title: "warnings.helper_permissions.title",
paragraphs: { return [ paragraphs: { return [
"warnings.helper_permissions.description".localized, "warnings.helper_permissions.description",
"warnings.helper_permissions.unavailable".localized, "warnings.helper_permissions.unavailable",
"warnings.helper_permissions.symlink".localized "warnings.helper_permissions.symlink"
] }, ] },
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries" url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries"
), ),
@@ -58,7 +58,7 @@ class WarningManager: ObservableObject {
return !PhpConfigChecker.shared.missing.isEmpty return !PhpConfigChecker.shared.missing.isEmpty
}, },
name: "Your PHP installation is missing configuration files", name: "Your PHP installation is missing configuration files",
title: "warnings.files_missing.title".localized, title: "warnings.files_missing.title",
paragraphs: { return [ paragraphs: { return [
"warnings.files_missing.description".localized( "warnings.files_missing.description".localized(
PhpConfigChecker.shared.missing.joined(separator: "\n") PhpConfigChecker.shared.missing.joined(separator: "\n")

View File

@@ -25,8 +25,6 @@ struct NoWarningsView: View {
} }
} }
struct NoWarningsView_Previews: PreviewProvider { #Preview {
static var previews: some View { NoWarningsView().padding()
NoWarningsView()
}
} }

View File

@@ -94,14 +94,12 @@ struct PhpDoctorView: View {
} }
} }
struct WarningListView_Previews: PreviewProvider { #Preview("Empty List") {
static var previews: some View { PhpDoctorView(empty: true, fake: true, manager: WarningManager())
PhpDoctorView(empty: true, fake: true, manager: WarningManager()) .frame(width: 600, height: 480)
.frame(width: 600, height: 480) }
.previewDisplayName("Empty List")
#Preview("List With All Warnings") {
PhpDoctorView(empty: false, fake: true, manager: WarningManager()) PhpDoctorView(empty: false, fake: true, manager: WarningManager())
.frame(width: 600, height: 480) .frame(width: 600, height: 480)
.previewDisplayName("List With All Warnings")
}
} }

View File

@@ -26,7 +26,7 @@ struct WarningView: View {
Text(title.localizedForSwiftUI) Text(title.localizedForSwiftUI)
.fontWeight(.bold) .fontWeight(.bold)
ForEach(paragraphs, id: \.self) { paragraph in ForEach(paragraphs, id: \.self) { paragraph in
Text(paragraph) Text(paragraph.localizedForSwiftUI)
.font(.system(size: 13)) .font(.system(size: 13))
} }
} }
@@ -47,23 +47,23 @@ struct WarningView: View {
} }
} }
struct WarningView_Previews: PreviewProvider { #Preview("Light Mode") {
static var previews: some View { WarningView(
WarningView( title: "warnings.helper_permissions.title",
title: "warnings.helper_permissions.title", paragraphs: ["warnings.helper_permissions.description"],
paragraphs: ["warnings.helper_permissions.description"], documentationUrl: "https://nicoverbruggen.be"
documentationUrl: "https://nicoverbruggen.be" )
) .frame(width: 600, height: 105)
.frame(width: 600, height: 105) .padding(25)
}
WarningView(
title: "warnings.helper_permissions.title", #Preview("Dark Mode") {
paragraphs: ["warnings.helper_permissions.description"], WarningView(
documentationUrl: "https://nicoverbruggen.be" title: "warnings.helper_permissions.title",
) paragraphs: ["warnings.helper_permissions.description"],
.preferredColorScheme(.dark) documentationUrl: "https://nicoverbruggen.be"
.frame(width: 600, height: 105) )
.preferredColorScheme(.dark)
// WarningListView().frame(width: 600, height: 580) .frame(width: 600, height: 105)
} .padding(25)
} }

View File

@@ -20,14 +20,21 @@ class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
prerelease: true prerelease: true
), ),
BrewPhpFormula( BrewPhpFormula(
name: "php@8.3", name: "php@8.4",
displayName: "PHP 8.4",
installedVersion: nil,
upgradeVersion: "8.4.0",
prerelease: true
),
BrewPhpFormula(
name: "php",
displayName: "PHP 8.3", displayName: "PHP 8.3",
installedVersion: nil, installedVersion: nil,
upgradeVersion: "8.3.0", upgradeVersion: "8.3.0",
prerelease: true prerelease: true
), ),
BrewPhpFormula( BrewPhpFormula(
name: "php", name: "php@8.2",
displayName: "PHP 8.2", displayName: "PHP 8.2",
installedVersion: "8.2.3", installedVersion: "8.2.3",
upgradeVersion: "8.2.4" upgradeVersion: "8.2.4"

View File

@@ -0,0 +1,163 @@
//
// PhpVersionManagerView+Interactivity.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 07/11/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import SwiftUI
extension PhpVersionManagerView {
public func runCommand(_ command: InstallAndUpgradeCommand) async {
if PhpEnvironments.shared.isBusy {
self.presentErrorAlert(
title: "phpman.action_prevented_busy.title".localized,
description: "phpman.action_prevented_busy.desc".localized,
button: "generic.ok".localized
)
return
}
do {
self.setBusyStatus(true)
try await command.execute { progress in
Task { @MainActor in
self.status.title = progress.title
self.status.description = progress.description
self.status.busy = progress.value != 1
// Whenever a key step is finished, refresh the PHP versions
if progress.value == 1 {
await self.handler.refreshPhpVersions(loadOutdated: false)
}
}
}
// Finally, after completing the command, also refresh PHP versions
await self.handler.refreshPhpVersions(loadOutdated: false)
// and mark the app as no longer busy
self.setBusyStatus(false)
} catch let error {
let error = error as! BrewCommandError
let messages = error.log.suffix(2).joined(separator: "\n")
self.setBusyStatus(false)
await self.handler.refreshPhpVersions(loadOutdated: false)
self.presentErrorAlert(
title: "phpman.failures.install.title".localized,
description: "phpman.failures.install.desc".localized(messages),
button: "generic.ok".localized
)
}
}
public func repairAll() async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.repairing".localized,
upgrading: [],
installing: []
))
}
public func upgradeAll(_ formulae: [BrewPhpFormula]) async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.updating".localized,
upgrading: formulae,
installing: []
))
}
public func install(_ formula: BrewPhpFormula) async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.installing".localized(formula.displayName),
upgrading: [],
installing: [formula]
))
}
public func confirmUninstall(_ formula: BrewPhpFormula) async {
// Disallow removal of the currently active versipn
if formula.installedVersion == PhpEnvironments.shared.currentInstall?.version.text {
self.presentErrorAlert(
title: "phpman.uninstall_prevented.title".localized,
description: "phpman.uninstall_prevented.desc".localized,
button: "generic.ok".localized
)
return
}
Alert.confirm(
onWindow: App.shared.phpVersionManagerWindowController!.window!,
messageText: "phpman.warnings.removal.title".localized(formula.displayName),
informativeText: "phpman.warnings.removal.desc".localized(formula.displayName),
buttonTitle: "phpman.warnings.removal.button".localized,
buttonIsDestructive: true,
secondButtonTitle: "generic.cancel".localized,
style: .warning,
onFirstButtonPressed: {
Task { await self.uninstall(formula) }
}
)
}
public func uninstall(_ formula: BrewPhpFormula) async {
let command = RemovePhpVersionCommand(formula: formula.name)
do {
self.setBusyStatus(true)
try await command.execute { progress in
Task { @MainActor in
self.status.title = progress.title
self.status.description = progress.description
self.status.busy = progress.value != 1
if progress.value == 1 {
await self.handler.refreshPhpVersions(loadOutdated: false)
self.setBusyStatus(false)
}
}
}
} catch {
self.setBusyStatus(false)
self.presentErrorAlert(
title: "phpman.failures.uninstall.title".localized,
description: "phpman.failures.uninstall.desc".localized(
"brew uninstall \(formula.name) --force"
),
button: "generic.ok".localized
)
}
}
public func setBusyStatus(_ busy: Bool) {
Task { @MainActor in
PhpEnvironments.shared.isBusy = busy
self.status.busy = busy
}
}
public func presentErrorAlert(
title: String,
description: String,
button: String,
style: NSAlert.Style = .critical
) {
Alert.confirm(
onWindow: App.shared.phpVersionManagerWindowController!.window!,
messageText: title,
informativeText: description,
buttonTitle: button,
secondButtonTitle: "",
style: style,
onFirstButtonPressed: {}
)
}
var hasUpdates: Bool {
return self.formulae.phpVersions.contains { formula in
return formula.hasUpgrade
}
}
}

View File

@@ -9,7 +9,6 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
// swiftlint:disable type_body_length
struct PhpVersionManagerView: View { struct PhpVersionManagerView: View {
@ObservedObject var formulae: BrewFormulaeObservable @ObservedObject var formulae: BrewFormulaeObservable
@ObservedObject var status: PhpFormulaeStatus @ObservedObject var status: PhpFormulaeStatus
@@ -132,240 +131,133 @@ struct PhpVersionManagerView: View {
.padding(10) .padding(10)
} }
BlockingOverlayView(busy: self.status.busy, title: self.status.title, text: self.status.description) { BlockingOverlayView(
List(Array(formulae.phpVersions.enumerated()), id: \.1.name) { (index, formula) in busy: self.status.busy,
HStack(alignment: .center, spacing: 7.0) { title: self.status.title,
Image(systemName: formula.icon) text: self.status.description
.resizable() ) {
.aspectRatio(contentMode: .fit) if #available(macOS 13, *) {
.frame(width: 16, height: 16) List(Array(formulae.phpVersions.enumerated()), id: \.1.name) { (index, formula) in
.foregroundColor(formula.iconColor) listContent(for: formula)
.padding(.horizontal, 5) .listRowBackground(
VStack(alignment: .leading, spacing: 2) { index % 2 == 0
HStack { ? Color.gray.opacity(0)
Text(formula.displayName).bold() : Color.gray.opacity(0.08)
)
if formula.prerelease { .padding(.vertical, 8)
Text("phpman.version.prerelease".localized.uppercased()) .padding(.horizontal, 8)
.font(.system(size: 9)) .listRowSeparator(.hidden)
.padding(.horizontal, 5)
.padding(.vertical, 1)
.background(Color.appPrimary)
.foregroundColor(Color.white)
.clipShape(Capsule())
.fixedSize(horizontal: true, vertical: true)
}
}
if formula.isInstalled && formula.hasUpgrade {
Text("phpman.version.has_update".localized(
formula.installedVersion!,
formula.upgradeVersion!
))
.font(.system(size: 11))
.foregroundColor(.gray)
} else if formula.isInstalled && formula.installedVersion != nil {
Text("phpman.version.installed".localized(formula.installedVersion!))
.font(.system(size: 11))
.foregroundColor(.gray)
} else {
Text("phpman.version.available_for_installation".localizedForSwiftUI)
.font(.system(size: 11))
.foregroundColor(.gray)
}
if !formula.healthy {
Text("phpman.version.broken".localizedForSwiftUI)
.font(.system(size: 11))
.foregroundColor(.red)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
if !formula.healthy {
Button("phpman.buttons.repair".localizedForSwiftUI, role: .destructive) {
Task { await self.repairAll() }
}
}
if formula.isInstalled {
Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) {
Task { await self.confirmUninstall(formula) }
}
} else {
Button("phpman.buttons.install".localizedForSwiftUI) {
Task { await self.install(formula) }
}
}
} }
.listRowBackground(index % 2 == 0 ? Color.gray.opacity(0): Color.gray.opacity(0.08)) .edgesIgnoringSafeArea(.top)
.padding(.vertical, 8) .listStyle(PlainListStyle())
.padding(.horizontal, 8) } else {
List(Array(formulae.phpVersions.enumerated()), id: \.1.name) { (index, formula) in
listContent(for: formula)
.listRowBackground(
index % 2 == 0
? Color.gray.opacity(0)
: Color.gray.opacity(0.08)
)
.padding(.vertical, 8)
.padding(.horizontal, 8)
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
} }
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
} }
}.frame(width: 600, height: 600) }.frame(width: 600, height: 600)
} }
public func runCommand(_ command: InstallAndUpgradeCommand) async { // MARK: View Functions
if PhpEnvironments.shared.isBusy {
self.presentErrorAlert(
title: "phpman.action_prevented_busy.title".localized,
description: "phpman.action_prevented_busy.desc".localized,
button: "generic.ok".localized
)
return
}
do { private var prereleaseBadge: some View {
self.setBusyStatus(true) Text("phpman.version.prerelease".localized.uppercased())
try await command.execute { progress in .font(.system(size: 9))
Task { @MainActor in .padding(.horizontal, 5)
self.status.title = progress.title .padding(.vertical, 1)
self.status.description = progress.description .background(Color.appPrimary)
self.status.busy = progress.value != 1 .foregroundColor(Color.white)
.clipShape(Capsule())
.fixedSize(horizontal: true, vertical: true)
}
// Whenever a key step is finished, refresh the PHP versions private func formulaButtons(for formula: BrewPhpFormula) -> some View {
if progress.value == 1 { HStack {
await self.handler.refreshPhpVersions(loadOutdated: false) if !formula.healthy {
} Button("phpman.buttons.repair".localizedForSwiftUI, role: .destructive) {
Task { await self.repairAll() }
} }
} }
// Finally, after completing the command, also refresh PHP versions
await self.handler.refreshPhpVersions(loadOutdated: false)
// and mark the app as no longer busy
self.setBusyStatus(false)
} catch let error {
let error = error as! BrewCommandError
let messages = error.log.suffix(2).joined(separator: "\n")
self.setBusyStatus(false) if formula.isInstalled {
await self.handler.refreshPhpVersions(loadOutdated: false) Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) {
Task { await self.confirmUninstall(formula) }
self.presentErrorAlert( }
title: "phpman.failures.install.title".localized, } else {
description: "phpman.failures.install.desc".localized(messages), Button("phpman.buttons.install".localizedForSwiftUI) {
button: "generic.ok".localized Task { await self.install(formula) }
)
}
}
public func repairAll() async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.repairing".localized,
upgrading: [],
installing: []
))
}
public func upgradeAll(_ formulae: [BrewPhpFormula]) async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.updating".localized,
upgrading: formulae,
installing: []
))
}
public func install(_ formula: BrewPhpFormula) async {
await self.runCommand(InstallAndUpgradeCommand(
title: "phpman.operations.installing".localized(formula.displayName),
upgrading: [],
installing: [formula]
))
}
public func confirmUninstall(_ formula: BrewPhpFormula) async {
// Disallow removal of the currently active versipn
if formula.installedVersion == PhpEnvironments.shared.currentInstall?.version.text {
self.presentErrorAlert(
title: "phpman.uninstall_prevented.title".localized,
description: "phpman.uninstall_prevented.desc".localized,
button: "generic.ok".localized
)
return
}
Alert.confirm(
onWindow: App.shared.phpVersionManagerWindowController!.window!,
messageText: "phpman.warnings.removal.title".localized(formula.displayName),
informativeText: "phpman.warnings.removal.desc".localized(formula.displayName),
buttonTitle: "phpman.warnings.removal.button".localized,
buttonIsDestructive: true,
secondButtonTitle: "generic.cancel".localized,
style: .warning,
onFirstButtonPressed: {
Task { await self.uninstall(formula) }
}
)
}
public func uninstall(_ formula: BrewPhpFormula) async {
let command = RemovePhpVersionCommand(formula: formula.name)
do {
self.setBusyStatus(true)
try await command.execute { progress in
Task { @MainActor in
self.status.title = progress.title
self.status.description = progress.description
self.status.busy = progress.value != 1
if progress.value == 1 {
await self.handler.refreshPhpVersions(loadOutdated: false)
self.setBusyStatus(false)
}
} }
} }
} catch {
self.setBusyStatus(false)
self.presentErrorAlert(
title: "phpman.failures.uninstall.title".localized,
description: "phpman.failures.uninstall.desc".localized(
"brew uninstall \(formula.name) --force"
),
button: "generic.ok".localized
)
} }
} }
public func setBusyStatus(_ busy: Bool) { private func formulaDescription(for formula: BrewPhpFormula) -> some View {
Task { @MainActor in VStack(alignment: .leading, spacing: 2) {
PhpEnvironments.shared.isBusy = busy HStack {
self.status.busy = busy Text(formula.displayName).bold()
if formula.prerelease {
prereleaseBadge
}
}
if formula.isInstalled && formula.hasUpgrade {
Text("phpman.version.has_update".localized(
formula.installedVersion!,
formula.upgradeVersion!
))
.font(.system(size: 11))
.foregroundColor(.gray)
} else if formula.isInstalled && formula.installedVersion != nil {
Text("phpman.version.installed".localized(formula.installedVersion!))
.font(.system(size: 11))
.foregroundColor(.gray)
} else {
Text("phpman.version.available_for_installation".localizedForSwiftUI)
.font(.system(size: 11))
.foregroundColor(.gray)
}
if !formula.healthy {
Text("phpman.version.broken".localizedForSwiftUI)
.font(.system(size: 11))
.foregroundColor(.red)
}
} }
.frame(maxWidth: .infinity, alignment: .leading)
} }
public func presentErrorAlert( private func formulaIcon(for formula: BrewPhpFormula) -> some View {
title: String, Image(systemName: formula.icon)
description: String, .resizable()
button: String, .aspectRatio(contentMode: .fit)
style: NSAlert.Style = .critical .frame(width: 16, height: 16)
) { .foregroundColor(formula.iconColor)
Alert.confirm( .padding(.horizontal, 5)
onWindow: App.shared.phpVersionManagerWindowController!.window!,
messageText: title,
informativeText: description,
buttonTitle: button,
secondButtonTitle: "",
style: style,
onFirstButtonPressed: {}
)
} }
var hasUpdates: Bool { private func listContent(for formula: BrewPhpFormula) -> some View {
return self.formulae.phpVersions.contains { formula in HStack(alignment: .center, spacing: 7.0) {
return formula.hasUpgrade formulaIcon(for: formula)
formulaDescription(for: formula)
formulaButtons(for: formula)
} }
} }
} }
// swiftlint:enable type_body_length
struct PhpVersionManagerView_Previews: PreviewProvider { #Preview {
static var previews: some View { PhpVersionManagerView(
PhpVersionManagerView( formulae: Brew.shared.formulae,
formulae: Brew.shared.formulae, handler: FakeBrewFormulaeHandler()
handler: FakeBrewFormulaeHandler() ).frame(width: 600, height: 600)
).frame(width: 600, height: 600)
}
} }