This commit is contained in:
Max Goedjen 2025-09-01 17:43:33 -07:00
parent ea96dd88eb
commit f3ce6b9d0f
No known key found for this signature in database
9 changed files with 138 additions and 50 deletions

View File

@ -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." : {

View File

@ -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()
}
}

View File

@ -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())
}

View File

@ -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()

View File

@ -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

View File

@ -113,7 +113,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
}
Button(.createSecretCreateButton, action: save)
.keyboardShortcut(.return)
.primary()
.primaryButton()
.disabled(name.isEmpty)
}
.padding()

View File

@ -45,7 +45,7 @@ struct EditSecretView<StoreType: SecretStoreModifiable>: View {
Button(.editSaveButton, action: rename)
.disabled(name.isEmpty)
.keyboardShortcut(.return)
.primary()
.primaryButton()
}
.padding()
}

View File

@ -22,18 +22,46 @@ struct IntegrationsView: View {
}
} detail: {
IntegrationsDetailView(selectedInstruction: $selectedInstruction)
.fauxToolbar {
Button("Done") {
dismiss()
}
.normalButton()
}
}
.onAppear {
selectedInstruction = instructions.gettingStarted
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Done") {
dismiss()
.frame(minHeight: 500)
}
.styled
}
extension View {
func fauxToolbar<Content: View>(content: () -> Content) -> some View {
modifier(FauxToolbarModifier(toolbarContent: content()))
}
}
struct FauxToolbarModifier<ToolbarContent: View>: 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)
}
}
}
}

View File

@ -5,19 +5,25 @@ 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,75 +35,94 @@ struct SetupView: View {
description: "setup_updates_description",
systemImage: "network.badge.shield.half.filled",
) {
OnboardingButton("setup_updates_ok", updates) {
Task {
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
let width: CGFloat?
@State var currentWidth: CGFloat?
init(_ label: LocalizedStringResource, _ complete: Bool, action: @escaping () -> Void) {
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")
}
}
.padding(.vertical, 2)
}
.disabled(complete)
.styled
}
}
extension View {
@ViewBuilder
var styled: some View {
if #available(macOS 26.0, *) {
buttonStyle(.glassProminent)
} else {
buttonStyle(.borderedProminent)
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)
.tint(complete ? .green : nil)
}
}
@ -126,6 +151,7 @@ struct StepView<Content: View>: View {
.bold()
Text(description)
}
Spacer()
actions
}
.padding(20)