From 091c026231220e6c7019ed94146c6be83de4dbdd Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Fri, 27 Feb 2026 14:09:23 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20WIP:=20Refactoring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Startup/StartupAlertButtonRow.swift | 27 +++- .../SwiftUI/Startup/StartupAlertView.swift | 123 ++++++++++-------- .../Startup/StartupAlertViewModel.swift | 5 +- 3 files changed, 100 insertions(+), 55 deletions(-) diff --git a/phpmon/Domain/SwiftUI/Startup/StartupAlertButtonRow.swift b/phpmon/Domain/SwiftUI/Startup/StartupAlertButtonRow.swift index f995d1e7..66d433fa 100644 --- a/phpmon/Domain/SwiftUI/Startup/StartupAlertButtonRow.swift +++ b/phpmon/Domain/SwiftUI/Startup/StartupAlertButtonRow.swift @@ -29,7 +29,6 @@ struct StartupAlertButtonRow: View { onQuit() } .focused($focusedButton, equals: .quit) - .disabled(state == .running) Spacer() @@ -64,6 +63,22 @@ struct StartupAlertButtonRow: View { .font(.subheadline) .foregroundStyle(.secondary) } + + case .failed: + HStack(spacing: 6) { + Image(systemName: "xmark.circle.fill") + .foregroundStyle(.red) + Text("Fix did not resolve the issue.") + .font(.subheadline) + .foregroundStyle(.secondary) + } + + Spacer() + + Button("startup.alert.retry".localized) { + onRetry() + } + .focused($focusedButton, equals: .retry) } } .padding(20) @@ -99,10 +114,18 @@ struct StartupAlertButtonRow: View { .frame(width: 460) } -#Preview("Fix succeeded") { +#Preview("Fix Succeeded") { StartupAlertButtonRow( state: .completed, hasFix: true, onQuit: {}, onRetry: {}, onFix: {} ) .frame(width: 460) } + +#Preview("Fix Failed") { + StartupAlertButtonRow( + state: .failed, hasFix: true, + onQuit: {}, onRetry: {}, onFix: {} + ) + .frame(width: 460) +} diff --git a/phpmon/Domain/SwiftUI/Startup/StartupAlertView.swift b/phpmon/Domain/SwiftUI/Startup/StartupAlertView.swift index efaf687a..4ec84f50 100644 --- a/phpmon/Domain/SwiftUI/Startup/StartupAlertView.swift +++ b/phpmon/Domain/SwiftUI/Startup/StartupAlertView.swift @@ -30,14 +30,16 @@ struct StartupAlertView: View { subtitleText: viewModel.check.subtitleText ) - if viewModel.state == .running || (viewModel.hasFix && viewModel.state == .idle) { + if viewModel.state == .running + || viewModel.state == .failed + || (viewModel.hasFix && viewModel.state == .idle) { Divider() VStack(alignment: .leading, spacing: 12) { - if viewModel.state == .running { + if viewModel.state == .running || viewModel.state == .failed { StartupOutputView( lines: viewModel.outputLines, - isRunning: true + isRunning: viewModel.state == .running ) } else { StartupFixCommandView( @@ -86,37 +88,38 @@ struct StartupAlertView: View { // MARK: - Previews -#Preview("Fix Available — brew link php") { - let check = EnvironmentCheck( - command: { _ in return true }, - fix: { _, output in output("Running brew link php...", .stdOut) }, - fixDescription: "brew link php", - name: "preview_php_binary", - titleText: "startup.errors.php_binary.title".localized, - subtitleText: "startup.errors.php_binary.subtitle".localized, - descriptionText: "startup.errors.php_binary.desc".localized( - App.shared.container.paths.php - ) +#Preview("No Fix Available") { + return StartupAlertView( + viewModel: StartupAlertViewModel(check: EnvironmentCheck( + command: { _ in return true }, + fix: nil, + name: "preview_php_binary", + titleText: "startup.errors.php_binary.title".localized, + subtitleText: "startup.errors.php_binary.subtitle".localized, + descriptionText: "startup.errors.php_binary.desc".localized( + App.shared.container.paths.php + ) + )) ) - let vm = StartupAlertViewModel(check: check) - return StartupAlertView(viewModel: vm) } -#Preview("Fix Available — valet trust") { - let check = EnvironmentCheck( - command: { _ in return true }, - fix: { _, output in output("Password required...", .stdOut) }, - fixDescription: "valet trust", - name: "preview_sudoers_brew", - titleText: "startup.errors.sudoers_brew.title".localized, - subtitleText: "startup.errors.sudoers_brew.subtitle".localized, - descriptionText: "startup.errors.sudoers_brew.desc".localized +#Preview("Fix Available") { + return StartupAlertView( + viewModel: StartupAlertViewModel(check: EnvironmentCheck( + command: { _ in return true }, + fix: { _, output in output("Running brew link php...", .stdOut) }, + fixDescription: "brew link php", + name: "preview_php_binary", + titleText: "startup.errors.php_binary.title".localized, + subtitleText: "startup.errors.php_binary.subtitle".localized, + descriptionText: "startup.errors.php_binary.desc".localized( + App.shared.container.paths.php + ) + )) ) - let vm = StartupAlertViewModel(check: check) - return StartupAlertView(viewModel: vm) } -#Preview("Fix Running — brew link php") { +#Preview("Fix Running") { StartupAlertView(viewModel: StartupAlertViewModel( check: EnvironmentCheck( command: { _ in return true }, @@ -132,34 +135,52 @@ struct StartupAlertView: View { state: .running, outputLines: [ OutputLine(text: "==> Linking Binary 'php' to '/opt/homebrew/bin/php'", stream: .stdOut), - OutputLine(text: "==> Downloading https://formulae.brew.sh/api/formula.jws.json", stream: .stdOut), - OutputLine(text: "Already downloaded: /Users/nico/Library/Caches/Homebrew/downloads/abc123.json", stream: .stdOut), - OutputLine(text: "Warning: php is keg-only and must be linked with --force", stream: .stdErr), OutputLine(text: "==> Linking php... linked 25 files", stream: .stdOut) ] )) } -#Preview("No Fix — Valet version unsupported") { - let check = EnvironmentCheck( - command: { _ in return true }, - name: "preview_valet_version", - titleText: "startup.errors.valet_version_not_supported.title".localized, - subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized, - descriptionText: "startup.errors.valet_version_not_supported.desc".localized - ) - let vm = StartupAlertViewModel(check: check) - return StartupAlertView(viewModel: vm) +#Preview("Fix Failed") { + StartupAlertView(viewModel: StartupAlertViewModel( + check: EnvironmentCheck( + command: { _ in return true }, + fix: { _, output in output("Running brew link php...", .stdOut) }, + fixDescription: "brew link php", + name: "preview_php_binary_failed", + titleText: "startup.errors.php_binary.title".localized, + subtitleText: "startup.errors.php_binary.subtitle".localized, + descriptionText: "startup.errors.php_binary.desc".localized( + App.shared.container.paths.php + ) + ), + state: .failed, + outputLines: [ + OutputLine(text: "==> Linking Binary 'php' to '/opt/homebrew/bin/php'", stream: .stdOut), + OutputLine(text: "Warning: php is keg-only and must be linked with --force", stream: .stdErr), + OutputLine(text: "", stream: .stdOut), + OutputLine(text: "---\nFix did not resolve the issue.", stream: .stdOut) + ] + )) } -#Preview("No Fix — Herd running") { - let check = EnvironmentCheck( - command: { _ in return true }, - name: "preview_herd_running", - titleText: "startup.errors.herd_running.title".localized, - subtitleText: "startup.errors.herd_running.subtitle".localized, - descriptionText: "startup.errors.herd_running.desc".localized - ) - let vm = StartupAlertViewModel(check: check) - return StartupAlertView(viewModel: vm) +#Preview("Fix Completed") { + StartupAlertView(viewModel: StartupAlertViewModel( + check: EnvironmentCheck( + command: { _ in return true }, + fix: { _, output in output("Running brew link php...", .stdOut) }, + fixDescription: "brew link php", + name: "preview_php_binary_completed", + titleText: "startup.errors.php_binary.title".localized, + subtitleText: "startup.errors.php_binary.subtitle".localized, + descriptionText: "startup.errors.php_binary.desc".localized( + App.shared.container.paths.php + ) + ), + state: .completed, + outputLines: [ + OutputLine(text: "==> Linking Binary 'php' to '/opt/homebrew/bin/php'", stream: .stdOut), + OutputLine(text: "==> Linking php... linked 25 files", stream: .stdOut), + OutputLine(text: "---\nFix applied successfully! Continuing...", stream: .stdOut) + ] + )) } diff --git a/phpmon/Domain/SwiftUI/Startup/StartupAlertViewModel.swift b/phpmon/Domain/SwiftUI/Startup/StartupAlertViewModel.swift index 89e74f7d..43d9daca 100644 --- a/phpmon/Domain/SwiftUI/Startup/StartupAlertViewModel.swift +++ b/phpmon/Domain/SwiftUI/Startup/StartupAlertViewModel.swift @@ -13,6 +13,7 @@ class StartupAlertViewModel: ObservableObject { case idle case running case completed + case failed } /// The actual check that is associated with this alert modal @@ -97,12 +98,12 @@ class StartupAlertViewModel: ObservableObject { } @MainActor private func fail() { - self.state = .idle + self.state = .failed self.outputLines.append(OutputLine(text: "---\nFix did not resolve the issue.", stream: .stdErr)) } @MainActor private func errorAndIdle(_ error: Error) { - self.state = .idle + self.state = .failed self.outputLines.append(OutputLine(text: "---\nError: \(error.localizedDescription)", stream: .stdErr)) }