From 3b093379b85d92c084a2429075e86ee67e6b2c10 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 19 Sep 2020 16:10:10 -0700 Subject: [PATCH] Facelift for detail view. --- Secretive/Views/SecretDetailView.swift | 147 ++++++++++++++++++++----- 1 file changed, 117 insertions(+), 30 deletions(-) diff --git a/Secretive/Views/SecretDetailView.swift b/Secretive/Views/SecretDetailView.swift index 2aad208..31dc74f 100644 --- a/Secretive/Views/SecretDetailView.swift +++ b/Secretive/Views/SecretDetailView.swift @@ -4,40 +4,16 @@ import SecretKit struct SecretDetailView: View { @State var secret: SecretType - + private let keyWriter = OpenSSHKeyWriter() var body: some View { Form { Section { - GroupBox(label: Text("Fingerprint")) { - HStack { - Text(keyWriter.openSSHFingerprint(secret: secret)) - Spacer() - } - .frame(minWidth: 150, maxWidth: .infinity) - .padding() - }.onDrag { - return NSItemProvider(item: NSData(data: keyWriter.openSSHFingerprint(secret: secret).data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) - } - Spacer().frame(height: 10) - GroupBox(label: Text("Public Key")) { - VStack(alignment: .leading) { - Text(keyWriter.openSSHString(secret: secret)) - .multilineTextAlignment(.leading) - HStack { - Spacer() - Button(action: copy) { - Text("Copy") - } - } - } - .frame(minWidth: 150, maxWidth: .infinity) - .padding() - } - .onDrag { - return NSItemProvider(item: NSData(data: keyString.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) - } + CopyableView(title: "Fingerprint", image: Image(systemName: "touchid"), text: keyWriter.openSSHFingerprint(secret: secret)) + Spacer() + .frame(height: 20) + CopyableView(title: "Public Key", image: Image(systemName: "key"), text: keyWriter.openSSHString(secret: secret)) Spacer() } } @@ -55,7 +31,6 @@ struct SecretDetailView: View { NSPasteboard.general.setString(keyString, forType: .string) } - } struct SecretDetailView_Previews: PreviewProvider { @@ -63,3 +38,115 @@ struct SecretDetailView_Previews: PreviewProvider { SecretDetailView(secret: Preview.Store(numberOfRandomSecrets: 1).secrets[0]) } } + +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) + .foregroundColor(primaryTextColor) + Text(title) + .font(.headline) + .foregroundColor(primaryTextColor) + Spacer() + 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)) + } + .frame(minWidth: 150, maxWidth: .infinity) + .background(backgroundColor) + .cornerRadius(10) + .onHover { hovering in + interactionState = hovering ? .hovering : .normal + } + .onDrag { + NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String) + } + .animation(.spring()) + .onTapGesture { + copy() + interactionState = .clicking + } + .gesture( + TapGesture() + .onEnded { + interactionState = .normal + } + ) + } + + var hoverText: String { + switch interactionState { + case .hovering: + return "Click to Copy" + case .clicking: + return "Copied!" + case .normal: + return "" + } + + } + + 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 + } + +}