mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-08-19 11:40:56 +00:00
parent
197f63d1eb
commit
609adf04bf
@ -8,9 +8,8 @@ struct CopyableView: View {
|
|||||||
var text: String
|
var text: String
|
||||||
|
|
||||||
@State private var interactionState: InteractionState = .normal
|
@State private var interactionState: InteractionState = .normal
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
|
||||||
|
var content: some View {
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack {
|
HStack {
|
||||||
image
|
image
|
||||||
@ -22,7 +21,7 @@ struct CopyableView: View {
|
|||||||
.foregroundColor(primaryTextColor)
|
.foregroundColor(primaryTextColor)
|
||||||
Spacer()
|
Spacer()
|
||||||
if interactionState != .normal {
|
if interactionState != .normal {
|
||||||
Text(hoverText)
|
hoverIcon
|
||||||
.bold()
|
.bold()
|
||||||
.textCase(.uppercase)
|
.textCase(.uppercase)
|
||||||
.foregroundColor(secondaryTextColor)
|
.foregroundColor(secondaryTextColor)
|
||||||
@ -39,17 +38,23 @@ struct CopyableView: View {
|
|||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.leading)
|
||||||
.font(.system(.body, design: .monospaced))
|
.font(.system(.body, design: .monospaced))
|
||||||
}
|
}
|
||||||
.background(backgroundColor)
|
._background(interactionState: interactionState)
|
||||||
.frame(minWidth: 150, maxWidth: .infinity)
|
.frame(minWidth: 150, maxWidth: .infinity)
|
||||||
.cornerRadius(10)
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
content
|
||||||
.onHover { hovering in
|
.onHover { hovering in
|
||||||
withAnimation {
|
withAnimation {
|
||||||
interactionState = hovering ? .hovering : .normal
|
interactionState = hovering ? .hovering : .normal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onDrag {
|
.onDrag({
|
||||||
NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: UTType.utf8PlainText.identifier)
|
NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: UTType.utf8PlainText.identifier)
|
||||||
}
|
}, preview: {
|
||||||
|
content
|
||||||
|
._background(interactionState: .dragging)
|
||||||
|
})
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
copy()
|
copy()
|
||||||
withAnimation {
|
withAnimation {
|
||||||
@ -66,31 +71,23 @@ struct CopyableView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hoverText: LocalizedStringKey {
|
@ViewBuilder
|
||||||
|
var hoverIcon: some View {
|
||||||
switch interactionState {
|
switch interactionState {
|
||||||
case .hovering:
|
case .hovering:
|
||||||
return "copyable_click_to_copy_button"
|
Image(systemName: "document.on.document")
|
||||||
|
.accessibilityLabel(String(localized: "copyable_click_to_copy_button"))
|
||||||
case .clicking:
|
case .clicking:
|
||||||
return "copyable_copied"
|
Image(systemName: "checkmark.circle.fill")
|
||||||
case .normal:
|
.accessibilityLabel(String(localized: "copyable_copied"))
|
||||||
fatalError()
|
case .normal, .dragging:
|
||||||
}
|
EmptyView()
|
||||||
}
|
|
||||||
|
|
||||||
var backgroundColor: Color {
|
|
||||||
switch interactionState {
|
|
||||||
case .normal:
|
|
||||||
return colorScheme == .dark ? Color(white: 0.2) : Color(white: 0.885)
|
|
||||||
case .hovering:
|
|
||||||
return colorScheme == .dark ? Color(white: 0.275) : Color(white: 0.82)
|
|
||||||
case .clicking:
|
|
||||||
return .accentColor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var primaryTextColor: Color {
|
var primaryTextColor: Color {
|
||||||
switch interactionState {
|
switch interactionState {
|
||||||
case .normal, .hovering:
|
case .normal, .hovering, .dragging:
|
||||||
return Color(.textColor)
|
return Color(.textColor)
|
||||||
case .clicking:
|
case .clicking:
|
||||||
return .white
|
return .white
|
||||||
@ -99,7 +96,7 @@ struct CopyableView: View {
|
|||||||
|
|
||||||
var secondaryTextColor: Color {
|
var secondaryTextColor: Color {
|
||||||
switch interactionState {
|
switch interactionState {
|
||||||
case .normal, .hovering:
|
case .normal, .hovering, .dragging:
|
||||||
return Color(.secondaryLabelColor)
|
return Color(.secondaryLabelColor)
|
||||||
case .clicking:
|
case .clicking:
|
||||||
return .white
|
return .white
|
||||||
@ -111,10 +108,57 @@ struct CopyableView: View {
|
|||||||
NSPasteboard.general.setString(text, forType: .string)
|
NSPasteboard.general.setString(text, forType: .string)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum InteractionState {
|
}
|
||||||
case normal, hovering, clicking
|
|
||||||
|
fileprivate enum InteractionState {
|
||||||
|
case normal, hovering, clicking, dragging
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
|
||||||
|
fileprivate func _background(interactionState: InteractionState) -> some View {
|
||||||
|
modifier(BackgroundViewModifier(interactionState: interactionState))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate struct BackgroundViewModifier: ViewModifier {
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
|
let interactionState: InteractionState
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if interactionState == .dragging {
|
||||||
|
content
|
||||||
|
.background(backgroundColor(interactionState: interactionState), in: RoundedRectangle(cornerRadius: 15))
|
||||||
|
} else {
|
||||||
|
if #available(macOS 26.0, *) {
|
||||||
|
content
|
||||||
|
// Very thin opacity lets user hover anywhere over the view, glassEffect doesn't allow.
|
||||||
|
.background(.white.opacity(0.01), in: RoundedRectangle(cornerRadius: 15))
|
||||||
|
.glassEffect(.regular.tint(backgroundColor(interactionState: interactionState)), in: RoundedRectangle(cornerRadius: 15))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
.background(backgroundColor(interactionState: interactionState))
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func backgroundColor(interactionState: InteractionState) -> Color {
|
||||||
|
switch interactionState {
|
||||||
|
case .normal:
|
||||||
|
return colorScheme == .dark ? Color(white: 0.2) : Color(white: 0.885)
|
||||||
|
case .hovering, .dragging:
|
||||||
|
return colorScheme == .dark ? Color(white: 0.275) : Color(white: 0.82)
|
||||||
|
case .clicking:
|
||||||
|
return .accentColor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
Loading…
Reference in New Issue
Block a user