From f3ce6b9d0fd05c4b27c83d47a9343989edf3a72d Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Mon, 1 Sep 2025 17:43:33 -0700 Subject: [PATCH] WIP --- Sources/Packages/Localizable.xcstrings | 9 ++ Sources/Secretive/App.swift | 6 +- .../Secretive/Views/ActionButtonStyle.swift | 29 +++++- Sources/Secretive/Views/AgentStatusView.swift | 2 +- Sources/Secretive/Views/ContentView.swift | 2 +- .../Secretive/Views/CreateSecretView.swift | 2 +- Sources/Secretive/Views/EditSecretView.swift | 2 +- .../Secretive/Views/IntegrationsView.swift | 42 +++++++-- Sources/Secretive/Views/SetupView.swift | 94 ++++++++++++------- 9 files changed, 138 insertions(+), 50 deletions(-) diff --git a/Sources/Packages/Localizable.xcstrings b/Sources/Packages/Localizable.xcstrings index ecc590c..9a78244 100644 --- a/Sources/Packages/Localizable.xcstrings +++ b/Sources/Packages/Localizable.xcstrings @@ -1186,6 +1186,9 @@ }, "Configure" : { + }, + "Configure Integrations" : { + }, "Configuring Tools for Secretive" : { @@ -3974,6 +3977,9 @@ } } } + }, + "Setup" : { + }, "setup_agent_activity_monitor_description" : { "extractionState" : "manual", @@ -5287,6 +5293,9 @@ }, "System" : { + }, + "Tell the tools you use how to talk to Secretive." : { + }, "There's a community-maintained list of instructions for apps on GitHub. If the app you're looking for isn't supported, create an issue and the community may be able to help." : { diff --git a/Sources/Secretive/App.swift b/Sources/Secretive/App.swift index bbd25c4..7e6c83d 100644 --- a/Sources/Secretive/App.swift +++ b/Sources/Secretive/App.swift @@ -61,7 +61,6 @@ struct Secretive: App { } .sheet(isPresented: $showingIntegrations) { IntegrationsView() - .frame(minHeight: 400) } } .commands { @@ -81,6 +80,11 @@ struct Secretive: App { NSWorkspace.shared.open(Constants.helpURL) } } + CommandGroup(after: .help) { + Button("Setup") { + showingSetup = true + } + } SidebarCommands() } } diff --git a/Sources/Secretive/Views/ActionButtonStyle.swift b/Sources/Secretive/Views/ActionButtonStyle.swift index 1f6afdc..74284a7 100644 --- a/Sources/Secretive/Views/ActionButtonStyle.swift +++ b/Sources/Secretive/Views/ActionButtonStyle.swift @@ -3,10 +3,11 @@ import SwiftUI struct PrimaryButtonModifier: ViewModifier { @Environment(\.colorScheme) var colorScheme + @Environment(\.isEnabled) var isEnabled func body(content: Content) -> some View { // Tinted glass prominent is really hard to read on 26.0. - if #available(macOS 26.0, *), colorScheme == .dark { + if #available(macOS 26.0, *), colorScheme == .dark, isEnabled { content.buttonStyle(.glassProminent) } else { content.buttonStyle(.borderedProminent) @@ -17,13 +18,13 @@ struct PrimaryButtonModifier: ViewModifier { extension View { - func primary() -> some View { + func primaryButton() -> some View { modifier(PrimaryButtonModifier()) } } -struct NormalButtonModifier: ViewModifier { +struct MenuButtonModifier: ViewModifier { func body(content: Content) -> some View { if #available(macOS 26.0, *) { @@ -39,7 +40,27 @@ struct NormalButtonModifier: ViewModifier { extension View { - func normal() -> some View { + func menuButton() -> some View { + modifier(MenuButtonModifier()) + } + +} + +struct NormalButtonModifier: ViewModifier { + + func body(content: Content) -> some View { + if #available(macOS 26.0, *) { + content.buttonStyle(.glass) + } else { + content.buttonStyle(.bordered) + } + } + +} + +extension View { + + func normalButton() -> some View { modifier(NormalButtonModifier()) } diff --git a/Sources/Secretive/Views/AgentStatusView.swift b/Sources/Secretive/Views/AgentStatusView.swift index 6af8df5..931f449 100644 --- a/Sources/Secretive/Views/AgentStatusView.swift +++ b/Sources/Secretive/Views/AgentStatusView.swift @@ -127,7 +127,7 @@ struct AgentNotRunningView: View { } } } - .primary() + .primaryButton() } else { Text("Secretive was unable to get SecretAgent to launch. Please try restarting your Mac, and if that doesn't work, file an issue on GitHub.") .bold() diff --git a/Sources/Secretive/Views/ContentView.swift b/Sources/Secretive/Views/ContentView.swift index 8ef73a7..933013d 100644 --- a/Sources/Secretive/Views/ContentView.swift +++ b/Sources/Secretive/Views/ContentView.swift @@ -106,7 +106,7 @@ extension ContentView { Button(.appMenuNewSecretButton, systemImage: "plus") { showingCreation = true } - .normal() + .menuButton() .sheet(isPresented: $showingCreation) { if let modifiable = storeList.modifiableStore { CreateSecretView(store: modifiable) { created in diff --git a/Sources/Secretive/Views/CreateSecretView.swift b/Sources/Secretive/Views/CreateSecretView.swift index f3e8b03..bd317ae 100644 --- a/Sources/Secretive/Views/CreateSecretView.swift +++ b/Sources/Secretive/Views/CreateSecretView.swift @@ -113,7 +113,7 @@ struct CreateSecretView: View { } Button(.createSecretCreateButton, action: save) .keyboardShortcut(.return) - .primary() + .primaryButton() .disabled(name.isEmpty) } .padding() diff --git a/Sources/Secretive/Views/EditSecretView.swift b/Sources/Secretive/Views/EditSecretView.swift index 06dde39..0b2a6fc 100644 --- a/Sources/Secretive/Views/EditSecretView.swift +++ b/Sources/Secretive/Views/EditSecretView.swift @@ -45,7 +45,7 @@ struct EditSecretView: View { Button(.editSaveButton, action: rename) .disabled(name.isEmpty) .keyboardShortcut(.return) - .primary() + .primaryButton() } .padding() } diff --git a/Sources/Secretive/Views/IntegrationsView.swift b/Sources/Secretive/Views/IntegrationsView.swift index 1d4cef6..3c3439c 100644 --- a/Sources/Secretive/Views/IntegrationsView.swift +++ b/Sources/Secretive/Views/IntegrationsView.swift @@ -21,19 +21,47 @@ struct IntegrationsView: View { } } } detail: { - IntegrationsDetailView(selectedInstruction: $selectedInstruction) + IntegrationsDetailView(selectedInstruction: $selectedInstruction) + .fauxToolbar { + Button("Done") { + dismiss() + } + .normalButton() + } } .onAppear { selectedInstruction = instructions.gettingStarted } - .toolbar { - ToolbarItem(placement: .primaryAction) { - Button("Done") { - dismiss() - } - .styled + .frame(minHeight: 500) + } + +} + +extension View { + + func fauxToolbar(content: () -> Content) -> some View { + modifier(FauxToolbarModifier(toolbarContent: content())) + } + +} + +struct FauxToolbarModifier: ViewModifier { + + var toolbarContent: ToolbarContent + + func body(content: Content) -> some View { + VStack(alignment: .leading) { + content + Divider() + HStack { + Spacer() + toolbarContent + .padding(.top, 8) + .padding(.trailing, 16) + .padding(.bottom, 16) } } + } } diff --git a/Sources/Secretive/Views/SetupView.swift b/Sources/Secretive/Views/SetupView.swift index eaa1652..0adc864 100644 --- a/Sources/Secretive/Views/SetupView.swift +++ b/Sources/Secretive/Views/SetupView.swift @@ -4,20 +4,26 @@ struct SetupView: View { @Environment(\.dismiss) private var dismiss @Binding var setupComplete: Bool - + + @State var showingIntegrations = false + @State var buttonWidth: CGFloat? + @State var installed = false @State var updates = false - @State var sshConfig = false + @State var integrations = false + var allDone: Bool { + installed && updates && integrations + } var body: some View { VStack { - VStack(spacing: 0) { + VStack(alignment: .leading, spacing: 0) { StepView( title: "setup_agent_title", description: "setup_agent_description", systemImage: "lock.laptopcomputer", ) { - OnboardingButton("setup_agent_install_button", installed) { + OnboardingButton("setup_agent_install_button", installed, width: buttonWidth) { Task { installed = await LaunchAgentController().install() } @@ -29,78 +35,97 @@ struct SetupView: View { description: "setup_updates_description", systemImage: "network.badge.shield.half.filled", ) { - OnboardingButton("setup_updates_ok", updates) { - Task { - updates = true - } + OnboardingButton("setup_updates_ok", updates, width: buttonWidth) { + updates = true } } Divider() StepView( - title: "setup_ssh_title", - description: "setup_ssh_description", - systemImage: "network.badge.shield.half.filled", + title: "Configure Integrations", + description: "Tell the tools you use how to talk to Secretive.", + systemImage: "firewall", ) { - HStack { - OnboardingButton("Configure", false) { -// sshConfig = true - } + OnboardingButton("Configure", integrations, width: buttonWidth) { + showingIntegrations = true } } } + .onPreferenceChange(OnboardingButton.WidthKey.self) { width in + buttonWidth = width + } .background(.white.opacity(0.1), in: RoundedRectangle(cornerRadius: 10)) .frame(minWidth: 700, maxWidth: .infinity) HStack { Spacer() - Button("Done") {} - .styled + Button("Done") { + setupComplete = true + dismiss() + } + .disabled(!allDone) + .primaryButton() } } + .interactiveDismissDisabled() .padding() + .sheet(isPresented: $showingIntegrations, onDismiss: { + integrations = true + }, content: { + IntegrationsView() + }) } } struct OnboardingButton: View { + struct WidthKey: @MainActor PreferenceKey { + @MainActor static var defaultValue: CGFloat? = nil + static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) { + if let next = nextValue(), next > (value ?? -1) { + value = next + } + } + + } + let label: LocalizedStringResource let complete: Bool let action: () -> Void - - init(_ label: LocalizedStringResource, _ complete: Bool, action: @escaping () -> Void) { + let width: CGFloat? + @State var currentWidth: CGFloat? + + init(_ label: LocalizedStringResource, _ complete: Bool, width: CGFloat? = nil, action: @escaping () -> Void) { self.label = label self.complete = complete self.action = action + self.width = width } var body: some View { Button(action: action) { HStack(spacing: 6) { - Text(label) if complete { + Text("Done") Image(systemName: "checkmark.circle.fill") + } else { + Text(label) } } + .frame(width: width) .padding(.vertical, 2) + .onGeometryChange(for: CGFloat.self) { proxy in + proxy.size.width + } action: { newValue in + currentWidth = newValue + } } + .preference(key: WidthKey.self, value: currentWidth) + .primaryButton() .disabled(complete) - .styled + .tint(complete ? .green : nil) } } -extension View { - - @ViewBuilder - var styled: some View { - if #available(macOS 26.0, *) { - buttonStyle(.glassProminent) - } else { - buttonStyle(.borderedProminent) - } - } - -} - struct StepView: View { let title: LocalizedStringResource @@ -126,6 +151,7 @@ struct StepView: View { .bold() Text(description) } + Spacer() actions } .padding(20)