mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-06 19:40:08 +02:00
⬆️ Adopt #Preview, cleanup PHP Version Manager
This commit is contained in:
@ -122,6 +122,10 @@
|
||||
C41F3D08298AED0D0042ACBF /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D3660A29113F20006BD146 /* System.swift */; };
|
||||
C4205A7E27F4D21800191A39 /* 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 */; };
|
||||
C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1494,6 +1499,7 @@
|
||||
children = (
|
||||
C4D5576329C77CC5001A44CD /* PhpVersionManagerWindowController.swift */,
|
||||
C43931C429C4BD610069165B /* PhpVersionManagerView.swift */,
|
||||
C42106652AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift */,
|
||||
C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */,
|
||||
);
|
||||
path = UI;
|
||||
@ -2586,6 +2592,7 @@
|
||||
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */,
|
||||
54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
|
||||
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
|
||||
C42106662AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
|
||||
C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */,
|
||||
C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
|
||||
C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
|
||||
@ -2775,6 +2782,7 @@
|
||||
C471E81428F9BAE80021E251 /* NSWindowExtension.swift in Sources */,
|
||||
C43BCD4629FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */,
|
||||
C471E7D328F9BA8F0021E251 /* ActiveShell.swift in Sources */,
|
||||
C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
|
||||
C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */,
|
||||
C471E7DE28F9BAA30021E251 /* CommandProtocol.swift in Sources */,
|
||||
C471E81B28F9BB250021E251 /* BetterAlertVC.swift in Sources */,
|
||||
@ -2831,6 +2839,7 @@
|
||||
C471E89F28F9BB8F0021E251 /* ValetDomainScanner.swift in Sources */,
|
||||
C471E8A028F9BB8F0021E251 /* FakeDomainScanner.swift in Sources */,
|
||||
C471E8A228F9BB8F0021E251 /* AppDelegate.swift in Sources */,
|
||||
C42106692AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
|
||||
C43931CD29C4C03F0069165B /* Brew.swift in Sources */,
|
||||
C451AFF92969E40F0078E617 /* HelpButton.swift in Sources */,
|
||||
C4ACE9E429F84EDD00110766 /* PhpGuard.swift in Sources */,
|
||||
@ -3083,6 +3092,7 @@
|
||||
C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
|
||||
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */,
|
||||
C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */,
|
||||
C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
|
||||
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
|
||||
C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */,
|
||||
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */,
|
||||
|
@ -27,15 +27,15 @@ struct HelpButton: View {
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.focusable(false)
|
||||
}
|
||||
|
||||
struct HelpButton_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
HelpButton(action: {}).padding()
|
||||
.previewDisplayName("Light Mode")
|
||||
HelpButton(action: {}).padding().preferredColorScheme(.dark)
|
||||
.previewDisplayName("Dark Mode")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("Light Mode") {
|
||||
HelpButton(action: {})
|
||||
.padding(100)
|
||||
}
|
||||
|
||||
#Preview("Dark Mode") {
|
||||
HelpButton(action: {})
|
||||
.padding(100)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ struct NoDomainResults: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct NoDomainResults_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NoDomainResults()
|
||||
}
|
||||
#Preview {
|
||||
NoDomainResults()
|
||||
}
|
||||
|
@ -126,78 +126,82 @@ struct DisclaimerView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct VersionPopoverView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "amazingwebsite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: ""
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
.previewDisplayName("Unknown Requirement")
|
||||
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "amazingwebsite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.1"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
.previewDisplayName("Requirement Matches")
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0",
|
||||
isolated: "8.0"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
.previewDisplayName("Isolated")
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0",
|
||||
isolated: "7.4"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
.previewDisplayName("Isolated Mismatch")
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0"
|
||||
),
|
||||
validPhpVersions: [
|
||||
VersionNumber(major: 8, minor: 0, patch: 0),
|
||||
VersionNumber(major: 8, minor: 1, patch: 0)
|
||||
],
|
||||
parent: nil
|
||||
)
|
||||
.previewDisplayName("Recommend Alternatives")
|
||||
}
|
||||
#Preview("Unknown Requirement") {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "amazingwebsite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: ""
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
}
|
||||
|
||||
#Preview("Requirement Matches") {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "amazingwebsite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.1"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
}
|
||||
|
||||
#Preview("Isolated") {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0",
|
||||
isolated: "8.0"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
}
|
||||
|
||||
#Preview("Isolated Mismatch") {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0",
|
||||
isolated: "7.4"
|
||||
),
|
||||
validPhpVersions: [],
|
||||
parent: nil
|
||||
)
|
||||
}
|
||||
|
||||
#Preview("Recommend Alternatives") {
|
||||
VersionPopoverView(
|
||||
site: FakeValetSite(
|
||||
fakeWithName: "anothersite",
|
||||
tld: "test",
|
||||
secure: true,
|
||||
path: "/path/to/site",
|
||||
linked: true,
|
||||
constraint: "^8.0"
|
||||
),
|
||||
validPhpVersions: [
|
||||
VersionNumber(major: 8, minor: 0, patch: 0),
|
||||
VersionNumber(major: 8, minor: 1, patch: 0)
|
||||
],
|
||||
parent: nil
|
||||
)
|
||||
}
|
||||
|
@ -45,9 +45,7 @@ struct HeaderView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct HeaderView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HeaderView(text: "Hello world")
|
||||
.frame(width: 330.0)
|
||||
}
|
||||
#Preview {
|
||||
HeaderView(text: "Hello world")
|
||||
.frame(width: 330.0)
|
||||
}
|
||||
|
@ -172,23 +172,21 @@ struct ServiceView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ServicesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ServicesView(manager: FakeServicesManager(
|
||||
formulae: ["php", "nginx", "dnsmasq"],
|
||||
status: .active
|
||||
), perRow: 4)
|
||||
.frame(width: 330.0)
|
||||
.previewDisplayName("Active 1")
|
||||
|
||||
ServicesView(manager: FakeServicesManager(
|
||||
formulae: [
|
||||
"php", "nginx", "dnsmasq", "thing1",
|
||||
"thing2", "thing3", "thing4", "thing5"
|
||||
],
|
||||
status: .inactive
|
||||
), perRow: 4)
|
||||
.frame(width: 330.0)
|
||||
.previewDisplayName("Active 2")
|
||||
}
|
||||
#Preview("Active 1") {
|
||||
ServicesView(manager: FakeServicesManager(
|
||||
formulae: ["php", "nginx", "dnsmasq"],
|
||||
status: .active
|
||||
), perRow: 4)
|
||||
.frame(width: 330.0)
|
||||
}
|
||||
|
||||
#Preview("Active 2") {
|
||||
ServicesView(manager: FakeServicesManager(
|
||||
formulae: [
|
||||
"php", "nginx", "dnsmasq", "thing1",
|
||||
"thing2", "thing3", "thing4", "thing5"
|
||||
],
|
||||
status: .inactive
|
||||
), perRow: 4)
|
||||
.frame(width: 330.0)
|
||||
}
|
||||
|
@ -98,12 +98,10 @@ struct StatsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct StatsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
StatsView(
|
||||
memoryLimit: "1024 MB",
|
||||
maxPostSize: "1024 MB",
|
||||
maxUploadSize: "1024 MB"
|
||||
).frame(height: 100)
|
||||
}
|
||||
#Preview {
|
||||
StatsView(
|
||||
memoryLimit: "1024 MB",
|
||||
maxPostSize: "1024 MB",
|
||||
maxUploadSize: "1024 MB"
|
||||
).frame(height: 100)
|
||||
}
|
||||
|
@ -53,13 +53,11 @@ struct ProgressWindowView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ProgressWindowView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ProgressWindowView(
|
||||
subject: ProgressViewSubject(
|
||||
title: "Long running task",
|
||||
description: "Please be patient"
|
||||
)
|
||||
#Preview {
|
||||
ProgressWindowView(
|
||||
subject: ProgressViewSubject(
|
||||
title: "Long running task",
|
||||
description: "Please be patient"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -136,10 +136,6 @@ struct OnboardingView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct OnboardingView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
OnboardingView()
|
||||
}
|
||||
}
|
||||
#Preview {
|
||||
OnboardingView()
|
||||
}
|
||||
|
@ -98,19 +98,19 @@ struct ByteLimitView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ByteLimitView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PreferenceContainer(
|
||||
name: "Max Size",
|
||||
description:
|
||||
"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."
|
||||
) {
|
||||
ByteLimitView(preference: BytePhpPreference(key: "max_memory"))
|
||||
}.frame(width: 600, height: 200)
|
||||
|
||||
ConfigManagerView()
|
||||
.frame(width: 600, height: .infinity)
|
||||
.previewDisplayName("Config Manager")
|
||||
}
|
||||
#Preview("Byte Limit View") {
|
||||
PreferenceContainer(
|
||||
name: "Max Size",
|
||||
description:
|
||||
"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."
|
||||
) {
|
||||
ByteLimitView(preference: BytePhpPreference(key: "max_memory"))
|
||||
}.frame(width: 600, height: 200)
|
||||
}
|
||||
|
||||
#Preview("Config Manager") {
|
||||
ConfigManagerView()
|
||||
.frame(width: 600, height: .infinity)
|
||||
.previewDisplayName("Config Manager")
|
||||
}
|
||||
|
@ -84,10 +84,6 @@ struct ConfigManagerView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ConfigManagerView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ConfigManagerView()
|
||||
.frame(width: 600)
|
||||
.previewDisplayName("Live Preview")
|
||||
}
|
||||
#Preview {
|
||||
ConfigManagerView().frame(width: 600)
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ class WarningManager: ObservableObject {
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
||||
},
|
||||
name: "Running PHP Monitor with Rosetta on M1",
|
||||
title: "warnings.arm_compatibility.title".localized,
|
||||
paragraphs: { return ["warnings.arm_compatibility.description".localized] },
|
||||
title: "warnings.arm_compatibility.title",
|
||||
paragraphs: { return ["warnings.arm_compatibility.description"] },
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon"
|
||||
),
|
||||
Warning(
|
||||
@ -44,11 +44,11 @@ class WarningManager: ObservableObject {
|
||||
!FileSystem.isWriteableFile("/usr/local/bin/")
|
||||
},
|
||||
name: "Helpers cannot be symlinked and not in PATH",
|
||||
title: "warnings.helper_permissions.title".localized,
|
||||
title: "warnings.helper_permissions.title",
|
||||
paragraphs: { return [
|
||||
"warnings.helper_permissions.description".localized,
|
||||
"warnings.helper_permissions.unavailable".localized,
|
||||
"warnings.helper_permissions.symlink".localized
|
||||
"warnings.helper_permissions.description",
|
||||
"warnings.helper_permissions.unavailable",
|
||||
"warnings.helper_permissions.symlink"
|
||||
] },
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries"
|
||||
),
|
||||
@ -58,7 +58,7 @@ class WarningManager: ObservableObject {
|
||||
return !PhpConfigChecker.shared.missing.isEmpty
|
||||
},
|
||||
name: "Your PHP installation is missing configuration files",
|
||||
title: "warnings.files_missing.title".localized,
|
||||
title: "warnings.files_missing.title",
|
||||
paragraphs: { return [
|
||||
"warnings.files_missing.description".localized(
|
||||
PhpConfigChecker.shared.missing.joined(separator: "\n• ")
|
||||
|
@ -25,8 +25,6 @@ struct NoWarningsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct NoWarningsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NoWarningsView()
|
||||
}
|
||||
#Preview {
|
||||
NoWarningsView().padding()
|
||||
}
|
||||
|
@ -94,14 +94,12 @@ struct PhpDoctorView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct WarningListView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PhpDoctorView(empty: true, fake: true, manager: WarningManager())
|
||||
.frame(width: 600, height: 480)
|
||||
.previewDisplayName("Empty List")
|
||||
|
||||
PhpDoctorView(empty: false, fake: true, manager: WarningManager())
|
||||
.frame(width: 600, height: 480)
|
||||
.previewDisplayName("List With All Warnings")
|
||||
}
|
||||
#Preview("Empty List") {
|
||||
PhpDoctorView(empty: true, fake: true, manager: WarningManager())
|
||||
.frame(width: 600, height: 480)
|
||||
}
|
||||
|
||||
#Preview("List With All Warnings") {
|
||||
PhpDoctorView(empty: false, fake: true, manager: WarningManager())
|
||||
.frame(width: 600, height: 480)
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct WarningView: View {
|
||||
Text(title.localizedForSwiftUI)
|
||||
.fontWeight(.bold)
|
||||
ForEach(paragraphs, id: \.self) { paragraph in
|
||||
Text(paragraph)
|
||||
Text(paragraph.localizedForSwiftUI)
|
||||
.font(.system(size: 13))
|
||||
}
|
||||
}
|
||||
@ -47,23 +47,23 @@ struct WarningView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct WarningView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
WarningView(
|
||||
title: "warnings.helper_permissions.title",
|
||||
paragraphs: ["warnings.helper_permissions.description"],
|
||||
documentationUrl: "https://nicoverbruggen.be"
|
||||
)
|
||||
.frame(width: 600, height: 105)
|
||||
|
||||
WarningView(
|
||||
title: "warnings.helper_permissions.title",
|
||||
paragraphs: ["warnings.helper_permissions.description"],
|
||||
documentationUrl: "https://nicoverbruggen.be"
|
||||
)
|
||||
.preferredColorScheme(.dark)
|
||||
.frame(width: 600, height: 105)
|
||||
|
||||
// WarningListView().frame(width: 600, height: 580)
|
||||
}
|
||||
#Preview("Light Mode") {
|
||||
WarningView(
|
||||
title: "warnings.helper_permissions.title",
|
||||
paragraphs: ["warnings.helper_permissions.description"],
|
||||
documentationUrl: "https://nicoverbruggen.be"
|
||||
)
|
||||
.frame(width: 600, height: 105)
|
||||
.padding(25)
|
||||
}
|
||||
|
||||
#Preview("Dark Mode") {
|
||||
WarningView(
|
||||
title: "warnings.helper_permissions.title",
|
||||
paragraphs: ["warnings.helper_permissions.description"],
|
||||
documentationUrl: "https://nicoverbruggen.be"
|
||||
)
|
||||
.preferredColorScheme(.dark)
|
||||
.frame(width: 600, height: 105)
|
||||
.padding(25)
|
||||
}
|
||||
|
@ -20,14 +20,21 @@ class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
||||
prerelease: true
|
||||
),
|
||||
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",
|
||||
installedVersion: nil,
|
||||
upgradeVersion: "8.3.0",
|
||||
prerelease: true
|
||||
),
|
||||
BrewPhpFormula(
|
||||
name: "php",
|
||||
name: "php@8.2",
|
||||
displayName: "PHP 8.2",
|
||||
installedVersion: "8.2.3",
|
||||
upgradeVersion: "8.2.4"
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
struct PhpVersionManagerView: View {
|
||||
@ObservedObject var formulae: BrewFormulaeObservable
|
||||
@ObservedObject var status: PhpFormulaeStatus
|
||||
@ -132,240 +131,133 @@ struct PhpVersionManagerView: View {
|
||||
.padding(10)
|
||||
}
|
||||
|
||||
BlockingOverlayView(busy: self.status.busy, title: self.status.title, text: self.status.description) {
|
||||
List(Array(formulae.phpVersions.enumerated()), id: \.1.name) { (index, formula) in
|
||||
HStack(alignment: .center, spacing: 7.0) {
|
||||
Image(systemName: formula.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 16, height: 16)
|
||||
.foregroundColor(formula.iconColor)
|
||||
.padding(.horizontal, 5)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack {
|
||||
Text(formula.displayName).bold()
|
||||
|
||||
if formula.prerelease {
|
||||
Text("phpman.version.prerelease".localized.uppercased())
|
||||
.font(.system(size: 9))
|
||||
.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) }
|
||||
}
|
||||
}
|
||||
BlockingOverlayView(
|
||||
busy: self.status.busy,
|
||||
title: self.status.title,
|
||||
text: self.status.description
|
||||
) {
|
||||
if #available(macOS 13, *) {
|
||||
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)
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
.listRowBackground(index % 2 == 0 ? Color.gray.opacity(0): Color.gray.opacity(0.08))
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 8)
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
.listStyle(PlainListStyle())
|
||||
} 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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// MARK: View Functions
|
||||
|
||||
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
|
||||
private var prereleaseBadge: some View {
|
||||
Text("phpman.version.prerelease".localized.uppercased())
|
||||
.font(.system(size: 9))
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.vertical, 1)
|
||||
.background(Color.appPrimary)
|
||||
.foregroundColor(Color.white)
|
||||
.clipShape(Capsule())
|
||||
.fixedSize(horizontal: true, vertical: true)
|
||||
}
|
||||
|
||||
// Whenever a key step is finished, refresh the PHP versions
|
||||
if progress.value == 1 {
|
||||
await self.handler.refreshPhpVersions(loadOutdated: false)
|
||||
}
|
||||
private func formulaButtons(for formula: BrewPhpFormula) -> some View {
|
||||
HStack {
|
||||
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)
|
||||
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)
|
||||
}
|
||||
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) }
|
||||
}
|
||||
}
|
||||
} 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
|
||||
private func formulaDescription(for formula: BrewPhpFormula) -> some View {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack {
|
||||
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(
|
||||
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: {}
|
||||
)
|
||||
private func formulaIcon(for formula: BrewPhpFormula) -> some View {
|
||||
Image(systemName: formula.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 16, height: 16)
|
||||
.foregroundColor(formula.iconColor)
|
||||
.padding(.horizontal, 5)
|
||||
}
|
||||
|
||||
var hasUpdates: Bool {
|
||||
return self.formulae.phpVersions.contains { formula in
|
||||
return formula.hasUpgrade
|
||||
private func listContent(for formula: BrewPhpFormula) -> some View {
|
||||
HStack(alignment: .center, spacing: 7.0) {
|
||||
formulaIcon(for: formula)
|
||||
formulaDescription(for: formula)
|
||||
formulaButtons(for: formula)
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable type_body_length
|
||||
|
||||
struct PhpVersionManagerView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PhpVersionManagerView(
|
||||
formulae: Brew.shared.formulae,
|
||||
handler: FakeBrewFormulaeHandler()
|
||||
).frame(width: 600, height: 600)
|
||||
}
|
||||
#Preview {
|
||||
PhpVersionManagerView(
|
||||
formulae: Brew.shared.formulae,
|
||||
handler: FakeBrewFormulaeHandler()
|
||||
).frame(width: 600, height: 600)
|
||||
}
|
||||
|
Reference in New Issue
Block a user