diff --git a/Sources/Secretive/Controllers/URLs.swift b/Sources/Secretive/Controllers/URLs.swift index 7b63ea1..3ea1fe5 100644 --- a/Sources/Secretive/Controllers/URLs.swift +++ b/Sources/Secretive/Controllers/URLs.swift @@ -9,4 +9,17 @@ extension URL { static var socketPath: String { URL.agentHomeURL.appendingPathComponent("socket.ssh").path() } + +} + +extension String { + + var normalizedPathAndFolder: (String, String) { + // All foundation-based normalization methods replace this with the container directly. + let processedPath = replacingOccurrences(of: "~", with: "/Users/\(NSUserName())") + let url = URL(filePath: processedPath) + let folder = url.deletingLastPathComponent().path() + return (processedPath, folder) + } + } diff --git a/Sources/Secretive/Views/Configuration/ConfigurationItemView.swift b/Sources/Secretive/Views/Configuration/ConfigurationItemView.swift index 2c8520b..77e6a2e 100644 --- a/Sources/Secretive/Views/Configuration/ConfigurationItemView.swift +++ b/Sources/Secretive/Views/Configuration/ConfigurationItemView.swift @@ -40,10 +40,7 @@ struct ConfigurationItemView: View { .buttonStyle(.borderless) case .revealInFinder(let rawPath): Button(.revealInFinderButton, systemImage: "folder") { - // All foundation-based normalization methods replace this with the container directly. - let processedPath = rawPath.replacingOccurrences(of: "~", with: "/Users/\(NSUserName())") - let url = URL(filePath: processedPath) - let folder = url.deletingLastPathComponent().path() + let (processedPath, folder) = rawPath.normalizedPathAndFolder NSWorkspace.shared.selectFile(processedPath, inFileViewerRootedAtPath: folder) } .labelStyle(.iconOnly) diff --git a/Sources/Secretive/Views/Secrets/SecretDetailView.swift b/Sources/Secretive/Views/Secrets/SecretDetailView.swift index 679ed70..b3940ff 100644 --- a/Sources/Secretive/Views/Secrets/SecretDetailView.swift +++ b/Sources/Secretive/Views/Secrets/SecretDetailView.swift @@ -21,7 +21,7 @@ struct SecretDetailView: View { CopyableView(title: .secretDetailPublicKeyLabel, image: Image(systemName: "key"), text: keyString) Spacer() .frame(height: 20) - CopyableView(title: .secretDetailPublicKeyPathLabel, image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.publicKeyPath(for: secret)) + CopyableView(title: .secretDetailPublicKeyPathLabel, image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.publicKeyPath(for: secret), showRevealInFinder: true) Spacer() } } diff --git a/Sources/Secretive/Views/Views/CopyableView.swift b/Sources/Secretive/Views/Views/CopyableView.swift index c36af4b..5d5b431 100644 --- a/Sources/Secretive/Views/Views/CopyableView.swift +++ b/Sources/Secretive/Views/Views/CopyableView.swift @@ -6,6 +6,7 @@ struct CopyableView: View { var title: LocalizedStringResource var image: Image var text: String + var showRevealInFinder = false @State private var interactionState: InteractionState = .normal @@ -21,9 +22,12 @@ struct CopyableView: View { .foregroundColor(primaryTextColor) Spacer() if interactionState != .normal { - hoverIcon - .bold() - .textCase(.uppercase) + HStack { + if showRevealInFinder { + revealInFinderButton + } + copyButton + } .foregroundColor(secondaryTextColor) .transition(.opacity) } @@ -72,11 +76,18 @@ struct CopyableView: View { } @ViewBuilder - var hoverIcon: some View { + var copyButton: some View { switch interactionState { case .hovering: - Image(systemName: "document.on.document") - .accessibilityLabel(String(localized: .copyableClickToCopyButton)) + Button(.copyableClickToCopyButton, systemImage: "document.on.document") { + withAnimation { + // Button will eat the click, so we set interaction state manually. + interactionState = .clicking + } + copy() + } + .labelStyle(.iconOnly) + .buttonStyle(.borderless) case .clicking: Image(systemName: "checkmark.circle.fill") .accessibilityLabel(String(localized: .copyableCopied)) @@ -85,6 +96,15 @@ struct CopyableView: View { } } + var revealInFinderButton: some View { + Button(.revealInFinderButton, systemImage: "folder") { + let (processedPath, folder) = text.normalizedPathAndFolder + NSWorkspace.shared.selectFile(processedPath, inFileViewerRootedAtPath: folder) + } + .labelStyle(.iconOnly) + .buttonStyle(.borderless) + } + var primaryTextColor: Color { switch interactionState { case .normal, .hovering, .dragging: