secretive/Sources/Secretive/Views/CopyableView.swift

134 lines
4.0 KiB
Swift
Raw Permalink Normal View History

2020-09-22 06:12:50 +00:00
import SwiftUI
import UniformTypeIdentifiers
2020-09-22 06:12:50 +00:00
struct CopyableView: View {
var title: String
var image: Image
var text: String
@State private var interactionState: InteractionState = .normal
@Environment(\.colorScheme) private var colorScheme
2020-09-22 06:12:50 +00:00
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: UTType.utf8PlainText.identifier)
2020-09-22 06:12:50 +00:00
}
.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 {
switch interactionState {
case .normal:
return colorScheme == .dark ? Color(white: 0.2) : Color(white: 0.885)
2020-09-22 06:12:50 +00:00
case .hovering:
return colorScheme == .dark ? Color(white: 0.275) : Color(white: 0.82)
2020-09-22 06:12:50 +00:00
case .clicking:
return .accentColor
2020-09-22 06:12:50 +00:00
}
}
var primaryTextColor: Color {
switch interactionState {
case .normal, .hovering:
return Color(.textColor)
2020-09-22 06:12:50 +00:00
case .clicking:
return .white
2020-09-22 06:12:50 +00:00
}
}
var secondaryTextColor: Color {
switch interactionState {
case .normal, .hovering:
return Color(.secondaryLabelColor)
2020-09-22 06:12:50 +00:00
case .clicking:
return .white
2020-09-22 06:12:50 +00:00
}
}
func copy() {
NSPasteboard.general.declareTypes([.string], owner: nil)
NSPasteboard.general.setString(text, forType: .string)
}
private enum InteractionState {
case normal, hovering, clicking
}
}
#if DEBUG
struct CopyableView_Previews: PreviewProvider {
static var previews: some View {
Group {
CopyableView(title: "Title", image: Image(systemName: "figure.wave"), text: "Hello world.")
.padding()
2020-09-22 06:12:50 +00:00
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. ")
.padding()
2020-09-22 06:12:50 +00:00
}
}
}
#endif