From e2f519987f595d4308fcc8cbad7898f2ff41f703 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 20 Sep 2020 00:12:20 -0700 Subject: [PATCH] New onboarding flow. --- Secretive.xcodeproj/project.pbxproj | 12 +- Secretive/Views/ContentView.swift | 46 ++-- Secretive/Views/CopyableView.swift | 131 +++++++++ Secretive/Views/SecretDetailView.swift | 122 +-------- Secretive/Views/SetupView.swift | 351 ++++++++++++++----------- 5 files changed, 369 insertions(+), 293 deletions(-) create mode 100644 Secretive/Views/CopyableView.swift diff --git a/Secretive.xcodeproj/project.pbxproj b/Secretive.xcodeproj/project.pbxproj index 1701804..a34060a 100644 --- a/Secretive.xcodeproj/project.pbxproj +++ b/Secretive.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 50617DCE23FCECFA0099B055 /* SecureEnclaveSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */; }; 50617DD023FCED2C0099B055 /* SecureEnclave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */; }; 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; }; + 5066A6C22516F303004B5A36 /* SetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5066A6C12516F303004B5A36 /* SetupView.swift */; }; + 5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5066A6C72516FE6E004B5A36 /* CopyableView.swift */; }; 506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; }; 506772C92425BB8500034DED /* NoStoresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506772C82425BB8500034DED /* NoStoresView.swift */; }; 506772FF2426F3F400034DED /* Brief.h in Headers */ = {isa = PBXBuildFile; fileRef = 506772FD2426F3F400034DED /* Brief.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -78,7 +80,6 @@ 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; }; 50C385A3240789E600AF2719 /* OpenSSHReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A2240789E600AF2719 /* OpenSSHReader.swift */; }; 50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; }; - 50C385A9240B636500AF2719 /* SetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A8240B636500AF2719 /* SetupView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -234,6 +235,8 @@ 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveSecret.swift; sourceTree = ""; }; 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclave.swift; sourceTree = ""; }; 50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = ""; }; + 5066A6C12516F303004B5A36 /* SetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupView.swift; sourceTree = ""; }; + 5066A6C72516FE6E004B5A36 /* CopyableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableView.swift; sourceTree = ""; }; 506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; }; 506772C82425BB8500034DED /* NoStoresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStoresView.swift; sourceTree = ""; }; 506772FB2426F3F400034DED /* Brief.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Brief.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -283,7 +286,6 @@ 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStoreView.swift; sourceTree = ""; }; 50C385A2240789E600AF2719 /* OpenSSHReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OpenSSHReader.swift; path = SecretKit/Common/OpenSSH/OpenSSHReader.swift; sourceTree = SOURCE_ROOT; }; 50C385A42407A76D00AF2719 /* SecretDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretDetailView.swift; sourceTree = ""; }; - 50C385A8240B636500AF2719 /* SetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -510,7 +512,8 @@ 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */, 506772C82425BB8500034DED /* NoStoresView.swift */, 50153E1F250AFCB200525160 /* UpdateView.swift */, - 50C385A8240B636500AF2719 /* SetupView.swift */, + 5066A6C12516F303004B5A36 /* SetupView.swift */, + 5066A6C72516FE6E004B5A36 /* CopyableView.swift */, ); path = Views; sourceTree = ""; @@ -922,7 +925,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 50C385A9240B636500AF2719 /* SetupView.swift in Sources */, + 5066A6C22516F303004B5A36 /* SetupView.swift in Sources */, 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */, 5079BA0F250F29BF00EA86F4 /* StoreListView.swift in Sources */, @@ -932,6 +935,7 @@ 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */, 50153E20250AFCB200525160 /* UpdateView.swift in Sources */, 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */, + 5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */, 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */, 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */, 50617D8323FCE48E0099B055 /* App.swift in Sources */, diff --git a/Secretive/Views/ContentView.swift b/Secretive/Views/ContentView.swift index 5db6074..18c1b1c 100644 --- a/Secretive/Views/ContentView.swift +++ b/Secretive/Views/ContentView.swift @@ -53,18 +53,19 @@ extension ContentView { color = .orange } return ToolbarItem { - AnyView(Button(action: { - selectedUpdate = update - }, label: { - Text(text) - .font(.headline) - .foregroundColor(.white) - }) - .background(color) - .cornerRadius(5) - .popover(item: $selectedUpdate, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { update in - UpdateDetailView(update: update) - } + AnyView( + Button(action: { + selectedUpdate = update + }, label: { + Text(text) + .font(.headline) + .foregroundColor(.white) + }) + .background(color) + .cornerRadius(5) + .popover(item: $selectedUpdate, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { update in + UpdateDetailView(update: update) + } ) } } @@ -74,11 +75,13 @@ extension ContentView { return ToolbarItem { AnyView(Spacer()) } } return ToolbarItem { - AnyView(Button(action: { - showingCreation = true - }, label: { - Image(systemName: "plus") - })) + AnyView( + Button(action: { + showingCreation = true + }, label: { + Image(systemName: "plus") + }) + ) } } @@ -104,10 +107,11 @@ extension ContentView { .background(Color.orange) .cornerRadius(5) .popover(isPresented: $runningSetup, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { - SetupView { completed in - runningSetup = false - hasRunSetup = completed - } +// SetupView { completed in +// runningSetup = false +// hasRunSetup = completed +// } + SetupView(visible: $runningSetup) } ) } diff --git a/Secretive/Views/CopyableView.swift b/Secretive/Views/CopyableView.swift new file mode 100644 index 0000000..a2501d6 --- /dev/null +++ b/Secretive/Views/CopyableView.swift @@ -0,0 +1,131 @@ +import SwiftUI + +struct CopyableView: View { + + var title: String + var image: Image + var text: String + + @State private var interactionState: InteractionState = .normal + + var body: some View { + VStack(alignment: .leading) { + HStack { + image + .renderingMode(.template) + .imageScale(.large) + .foregroundColor(primaryTextColor) + Text(title) + .font(.headline) + .foregroundColor(primaryTextColor) + Spacer() + if interactionState != .normal { + Text(hoverText) + .bold() + .textCase(.uppercase) + .foregroundColor(secondaryTextColor) + .transition(.opacity) + } + + } + .padding(EdgeInsets(top: 20, leading: 20, bottom: 10, trailing: 20)) + Divider() + Text(text) + .fixedSize(horizontal: false, vertical: true) + .foregroundColor(primaryTextColor) + .padding(EdgeInsets(top: 10, leading: 20, bottom: 20, trailing: 20)) + .multilineTextAlignment(.leading) + .font(.system(.body, design: .monospaced)) + } + .background(backgroundColor) + .frame(minWidth: 150, maxWidth: .infinity) + .cornerRadius(10) + .onHover { hovering in + withAnimation { + interactionState = hovering ? .hovering : .normal + } + } + .onDrag { + NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) + } + .onTapGesture { + copy() + withAnimation { + interactionState = .clicking + } + } + .gesture( + TapGesture() + .onEnded { + withAnimation { + interactionState = .normal + } + } + ) + } + + var hoverText: String { + switch interactionState { + case .hovering: + return "Click to Copy" + case .clicking: + return "Copied" + case .normal: + fatalError() + } + } + + var backgroundColor: Color { + let color: NSColor + switch interactionState { + case .normal: + color = .windowBackgroundColor + case .hovering: + color = .unemphasizedSelectedContentBackgroundColor + case .clicking: + color = .selectedContentBackgroundColor + } + return Color(color) + } + + var primaryTextColor: Color { + let color: NSColor + switch interactionState { + case .normal, .hovering: + color = .textColor + case .clicking: + color = .white + } + return Color(color) + } + + var secondaryTextColor: Color { + let color: NSColor + switch interactionState { + case .normal, .hovering: + color = .secondaryLabelColor + case .clicking: + color = .white + } + return Color(color) + } + + func copy() { + NSPasteboard.general.declareTypes([.string], owner: nil) + NSPasteboard.general.setString(text, forType: .string) + } + + private enum InteractionState { + case normal, hovering, clicking + } + +} + +struct CopyableView_Previews: PreviewProvider { + static var previews: some View { + Group { + CopyableView(title: "Title", image: Image(systemName: "figure.wave"), text: "Hello world.") + CopyableView(title: "Title", image: Image(systemName: "figure.wave"), text: "Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. ") + } + } +} diff --git a/Secretive/Views/SecretDetailView.swift b/Secretive/Views/SecretDetailView.swift index 6c3d8da..bad69a7 100644 --- a/Secretive/Views/SecretDetailView.swift +++ b/Secretive/Views/SecretDetailView.swift @@ -18,8 +18,7 @@ struct SecretDetailView: View { } } .padding() - .frame(minHeight: 150, maxHeight: .infinity) - + .frame(minHeight: 200, maxHeight: .infinity) } var keyString: String { @@ -39,122 +38,3 @@ struct SecretDetailView_Previews: PreviewProvider { } } -struct CopyableView: View { - - var title: String - var image: Image - var text: String - - @State private var interactionState: InteractionState = .normal - - var body: some View { - VStack(alignment: .leading) { - HStack { - image - .renderingMode(.template) - .imageScale(.large) - .foregroundColor(primaryTextColor) - Text(title) - .font(.headline) - .foregroundColor(primaryTextColor) - Spacer() - if interactionState != .normal { - Text(hoverText) - .bold() - .textCase(.uppercase) - .foregroundColor(secondaryTextColor) - .transition(.opacity) - } - - } - .padding(EdgeInsets(top: 20, leading: 20, bottom: 10, trailing: 20)) - Divider() - Text(text) - .foregroundColor(primaryTextColor) - .padding(EdgeInsets(top: 10, leading: 20, bottom: 20, trailing: 20)) - .multilineTextAlignment(.leading) - .font(.system(.body, design: .monospaced)) - } - .background(backgroundColor) - .frame(minWidth: 150, maxWidth: .infinity) - .cornerRadius(10) - .onHover { hovering in - withAnimation { - interactionState = hovering ? .hovering : .normal - } - } - .onDrag { - NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) - } - .onTapGesture { - copy() - withAnimation { - interactionState = .clicking - } - } - .gesture( - TapGesture() - .onEnded { - withAnimation { - interactionState = .normal - } - } - ) - } - - var hoverText: String { - switch interactionState { - case .hovering: - return "Click to Copy" - case .clicking: - return "Copied!" - case .normal: - fatalError() - } - } - - var backgroundColor: Color { - let color: NSColor - switch interactionState { - case .normal: - color = .windowBackgroundColor - case .hovering: - color = .unemphasizedSelectedContentBackgroundColor - case .clicking: - color = .selectedContentBackgroundColor - } - return Color(color) - } - - var primaryTextColor: Color { - let color: NSColor - switch interactionState { - case .normal, .hovering: - color = .textColor - case .clicking: - color = .white - } - return Color(color) - } - - var secondaryTextColor: Color { - let color: NSColor - switch interactionState { - case .normal, .hovering: - color = .secondaryLabelColor - case .clicking: - color = .white - } - return Color(color) - } - - func copy() { - NSPasteboard.general.declareTypes([.string], owner: nil) - NSPasteboard.general.setString(text, forType: .string) - } - - private enum InteractionState { - case normal, hovering, clicking - } - -} diff --git a/Secretive/Views/SetupView.swift b/Secretive/Views/SetupView.swift index bbfa85b..7162380 100644 --- a/Secretive/Views/SetupView.swift +++ b/Secretive/Views/SetupView.swift @@ -1,168 +1,245 @@ -import Foundation import SwiftUI struct SetupView: View { - - var completion: ((Bool) -> Void)? - @State var completedSteps: Set = [] - - var body: some View { - Form { - SetupStepView(text: "Secretive needs to install a helper app to sign requests when the main app isn't running. This app is called \"SecretAgent\" and you might see it in Activity Manager from time to time.", - stepID: .agent, - nestedView: nil, - actionText: "Install") { - let success = installLaunchAgent() - if success { - completedSteps.insert(.agent) - } - return success - } - SetupStepView(text: "Add this line to your shell config telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.", - stepID: .shellConfig, - nestedView: SetupStepCommandView(instructions: Constants.socketPrompts, selectedShellInstruction: Constants.socketPrompts.first!), - actionText: "Added") { - markAsDone(.shellConfig) - } - SetupStepView(text: "Secretive will periodically check with GitHub to see if there's a new release. If you see any network requests to GitHub, that's why.", - stepID: .updateNotice, - nestedView: Link("Read more about this here.", destination: Constants.updaterFAQURL), - actionText: "Got it") { - markAsDone(.updateNotice) - } - HStack { - Spacer() - Button("Finish") { - completion?(completedAllSteps) - }.disabled(!completedAllSteps) - .padding() - } - }.frame(minWidth: 640, minHeight: 400) - } - -} -struct SetupStepView: View { - - let text: String - let stepID: Step - let nestedView: NestedViewType? - @State var completed = false - let actionText: String - let action: (() -> Bool) - + @State var stepIndex = 0 + @Binding var visible: Bool + var body: some View { - Section { - HStack { - ZStack { - if completed { - Circle().foregroundColor(.green) - .frame(width: 30, height: 30) - Text("✓") - .foregroundColor(.white) - .bold() - } else { - Circle().foregroundColor(.blue) - .frame(width: 30, height: 30) - Text(String(describing: stepID.rawValue + 1)) - .foregroundColor(.white) - .bold() + VStack { + StepView(numberOfSteps: 3, currentStep: stepIndex) + GeometryReader { proxy in + HStack { + SecretAgentSetupView(buttonAction: advance) + .frame(width: proxy.size.width) + SSHAgentSetupView(buttonAction: advance) + .frame(width: proxy.size.width) + UpdaterExplainerView { + visible = false } + .frame(width: proxy.size.width) } - .padding() - VStack { - Text(text) - .opacity(completed ? 0.5 : 1) - .lineLimit(nil) - if nestedView != nil { - nestedView!.padding() - } - } - .padding() - Button(actionText) { - completed = action() - }.frame(alignment: .trailing) - .disabled(completed) - .padding() + .offset(x: -proxy.size.width * CGFloat(stepIndex), y: 0) + .animation(.spring()) } } + .frame(idealWidth: 500, idealHeight: 500) } + + func advance() { + stepIndex += 1 + } + } -struct SetupStepCommandView: View { - - let instructions: [ShellConfigInstruction] +struct SetupView_Previews: PreviewProvider { - @State var selectedShellInstruction: ShellConfigInstruction + static var previews: some View { + Group { + SetupView(visible: .constant(true)) + } + } + +} + +struct StepView: View { + + let numberOfSteps: Int + let currentStep: Int var body: some View { - TabView(selection: $selectedShellInstruction) { - ForEach(instructions) { instruction in - VStack(alignment: .leading) { - Text(instruction.text) - .lineLimit(nil) - .font(.system(.caption, design: .monospaced)) - .multilineTextAlignment(.leading) - .frame(minHeight: 50) - HStack { - Spacer() - Button(action: copy) { - Text("Copy") + ZStack { + Rectangle() + .foregroundColor(.blue) + .frame(height: 5) + HStack { + ForEach(0.. index { + Circle() + .foregroundColor(.green) + .frame(width: 30, height: 30) + Text("✓") + .foregroundColor(.white) + .bold() + } else { + Circle() + .foregroundColor(currentStep == index ? .white : .blue) + .frame(width: 30, height: 30) + Text(String(describing: index + 1)) + .foregroundColor(currentStep == index ? .blue : .white) + .bold() } } - }.tabItem { - Text(instruction.shell) + if index < numberOfSteps - 1 { + Spacer(minLength: 30) + } } - .tag(instruction) - .padding() } } - .onDrag { - return NSItemProvider(item: NSData(data: selectedShellInstruction.text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) + .padding() + } + +} + +struct SetupStepView : View where Content : View { + + let title: String + let image: Image + let bodyText: String + let buttonTitle: String + let buttonAction: () -> Void + let content: Content + + init(title: String, image: Image, bodyText: String, buttonTitle: String, buttonAction: @escaping () -> Void = {}, @ViewBuilder content: () -> Content) { + self.title = title + self.image = image + self.bodyText = bodyText + self.buttonTitle = buttonTitle + self.buttonAction = buttonAction + self.content = content() + } + + var body: some View { + VStack { + Text(title) + .font(.title) + Spacer() + image + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 64) + Spacer() + Text(bodyText) + .multilineTextAlignment(.center) + Spacer() + content + Spacer() + Button(buttonTitle) { + buttonAction() + } + } + .padding() + } + +} + +struct SecretAgentSetupView: View { + + let buttonAction: () -> Void + + var body: some View { + SetupStepView(title: "Setup Secret Agent", + image: Image(nsImage: NSApp.applicationIconImage), + bodyText: "Secretive needs to set up a helper app to work properly. It will sign requests from SSH clients in the background, so you don't need to keep the main Secretive app open.", + buttonTitle: "Install", + buttonAction: install) { + (Text("This helper app is called ") + Text("Secret Agent").bold().underline() + Text(" and you may see it in Activity Manager from time to time.")) + .multilineTextAlignment(.center) } } - - func copy() { - NSPasteboard.general.declareTypes([.string], owner: nil) - NSPasteboard.general.setString(selectedShellInstruction.text, forType: .string) + + func install() { + _ = LaunchAgentController().install() + buttonAction() + } + +} + +struct SecretAgentSetupView_Previews: PreviewProvider { + + static var previews: some View { + Group { + SecretAgentSetupView(buttonAction: {}) + } + } + +} + +struct SSHAgentSetupView: View { + + @State var selectedShellInstruction: ShellConfigInstruction = SetupView.Constants.socketPrompts.first! + + let buttonAction: () -> Void + + var body: some View { + SetupStepView(title: "Configure your SSH Agent", + image: Image(systemName: "terminal"), + bodyText: "Add this line to your shell config telling SSH to talk to Secret Agent when it wants to authenticate. Drag this into your config file.", + buttonTitle: "Done", + buttonAction: buttonAction) { + Picker(selection: $selectedShellInstruction, label: EmptyView()) { + ForEach(SetupView.Constants.socketPrompts) { instruction in + Text(instruction.shell) + .tag(instruction) + .padding() + } + }.pickerStyle(SegmentedPickerStyle()) + CopyableView(title: "Add to \(selectedShellInstruction.shellConfigPath)", image: Image(systemName: "greaterthan.square"), text: selectedShellInstruction.text) + } + } + +} + +struct SSHAgentSetupView_Previews: PreviewProvider { + + static var previews: some View { + Group { + SSHAgentSetupView(buttonAction: {}) + } + } + +} + + +struct UpdaterExplainerView: View { + + let buttonAction: () -> Void + + var body: some View { + SetupStepView(title: "Updates", + image: Image(systemName: "dot.radiowaves.left.and.right"), + bodyText: "Secretive will periodically check with GitHub to see if there's a new release. If you see any network requests to GitHub, that's why.", + buttonTitle: "Okay", + buttonAction: buttonAction) { + Link("Read more about this here.", destination: SetupView.Constants.updaterFAQURL) + } + } + +} + +struct UpdaterExplainerView_Previews: PreviewProvider { + static var previews: some View { + Group { + UpdaterExplainerView(buttonAction: {}) + } } - } extension SetupView { - - func installLaunchAgent() -> Bool { - LaunchAgentController().install() - } - - func markAsDone(_ step: Step) -> Bool { - completedSteps.insert(step) - return true - } - var completedAllSteps: Bool { - completedSteps == Set(Step.allCases) - } - -} - -extension SetupView { - enum Constants { static let socketPath = (NSHomeDirectory().replacingOccurrences(of: "com.maxgoedjen.Secretive.Host", with: "com.maxgoedjen.Secretive.SecretAgent") as NSString).appendingPathComponent("socket.ssh") as String static let socketPrompts: [ShellConfigInstruction] = [ - ShellConfigInstruction(shell: "zsh", text: "export SSH_AUTH_SOCK=\(socketPath)"), - ShellConfigInstruction(shell: "bash", text: "export SSH_AUTH_SOCK=\(socketPath)"), - ShellConfigInstruction(shell: "fish", text: "set -x SSH_AUTH_SOCK=\(socketPath)"), + ShellConfigInstruction(shell: "zsh", + shellConfigPath: "~/.zshrc", + text: "export SSH_AUTH_SOCK=\(socketPath)"), + ShellConfigInstruction(shell: "bash", + shellConfigPath: "~/.bashrc", + text: "export SSH_AUTH_SOCK=\(socketPath)"), + ShellConfigInstruction(shell: "fish", + shellConfigPath: "~/.config/fish/config.fish", + text: "set -x SSH_AUTH_SOCK=\(socketPath)"), ] static let updaterFAQURL = URL(string: "https://github.com/maxgoedjen/secretive/blob/main/FAQ.md#whats-this-network-request-to-github")! } - + } struct ShellConfigInstruction: Identifiable, Hashable { var shell: String + var shellConfigPath: String var text: String var id: String { @@ -170,23 +247,3 @@ struct ShellConfigInstruction: Identifiable, Hashable { } } - -enum Step: Int, Identifiable, Hashable, CaseIterable { - - case agent, shellConfig, updateNotice - - var id: Int { - rawValue - } - -} - -struct SetupView_Previews: PreviewProvider { - static var previews: some View { - Group { - SetupView() - SetupView() - .frame(width: 1500, height: 400) - } - } -}