2023-01-17 10:36:01 +00:00
|
|
|
import DesignSystem
|
2022-12-19 16:18:16 +00:00
|
|
|
import Models
|
2023-02-19 14:29:07 +00:00
|
|
|
import Nuke
|
2022-12-25 06:43:02 +00:00
|
|
|
import NukeUI
|
2023-01-17 10:36:01 +00:00
|
|
|
import Shimmer
|
|
|
|
import SwiftUI
|
2022-12-19 16:18:16 +00:00
|
|
|
|
2023-02-17 12:30:56 +00:00
|
|
|
public struct StatusRowCardView: View {
|
2022-12-19 16:18:16 +00:00
|
|
|
@Environment(\.openURL) private var openURL
|
2023-02-19 14:29:07 +00:00
|
|
|
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
|
2023-02-21 06:23:42 +00:00
|
|
|
|
2023-02-19 14:29:07 +00:00
|
|
|
@EnvironmentObject private var theme: Theme
|
2023-02-22 18:09:39 +00:00
|
|
|
|
2022-12-23 09:41:55 +00:00
|
|
|
let card: Card
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 09:41:55 +00:00
|
|
|
public init(card: Card) {
|
|
|
|
self.card = card
|
|
|
|
}
|
2023-02-22 18:09:39 +00:00
|
|
|
|
2023-02-22 17:49:00 +00:00
|
|
|
private var maxWidth: CGFloat? {
|
|
|
|
if theme.statusDisplayStyle == .medium {
|
|
|
|
return 300
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2023-02-22 18:09:39 +00:00
|
|
|
|
2023-02-22 17:49:00 +00:00
|
|
|
private func imageWidthFor(proxy: GeometryProxy) -> CGFloat {
|
|
|
|
if theme.statusDisplayStyle == .medium, let maxWidth {
|
|
|
|
return maxWidth
|
|
|
|
}
|
|
|
|
return proxy.frame(in: .local).width
|
|
|
|
}
|
2023-02-22 18:09:39 +00:00
|
|
|
|
2023-02-22 17:49:00 +00:00
|
|
|
private var imageHeight: CGFloat {
|
|
|
|
if theme.statusDisplayStyle == .medium {
|
|
|
|
return 100
|
|
|
|
}
|
|
|
|
return 200
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 09:41:55 +00:00
|
|
|
public var body: some View {
|
2023-07-17 17:13:36 +00:00
|
|
|
Button {
|
|
|
|
if let url = URL(string: card.url) {
|
|
|
|
openURL(url)
|
|
|
|
}
|
|
|
|
} label: {
|
|
|
|
if let title = card.title, let url = URL(string: card.url) {
|
|
|
|
VStack(alignment: .leading) {
|
|
|
|
if let imageURL = card.image, !isInCaptureMode {
|
|
|
|
GeometryReader { proxy in
|
|
|
|
let width = imageWidthFor(proxy: proxy)
|
|
|
|
let processors: [ImageProcessing] = [.resize(size: .init(width: width, height: imageHeight))]
|
|
|
|
LazyImage(url: imageURL) { state in
|
|
|
|
if let image = state.image {
|
|
|
|
image
|
|
|
|
.resizable()
|
|
|
|
.aspectRatio(contentMode: .fill)
|
|
|
|
.frame(height: imageHeight)
|
|
|
|
.frame(maxWidth: width)
|
|
|
|
.clipped()
|
|
|
|
} else if state.isLoading {
|
|
|
|
Rectangle()
|
|
|
|
.fill(Color.gray)
|
|
|
|
.frame(height: imageHeight)
|
|
|
|
}
|
2023-02-17 18:11:09 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
.processors(processors)
|
|
|
|
// This image is decorative
|
|
|
|
.accessibilityHidden(true)
|
2022-12-19 16:18:16 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
.frame(height: imageHeight)
|
2022-12-25 06:43:02 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
HStack {
|
|
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
|
|
Text(title)
|
|
|
|
.font(.scaledHeadline)
|
2022-12-19 16:18:16 +00:00
|
|
|
.lineLimit(3)
|
2023-07-17 17:13:36 +00:00
|
|
|
if let description = card.description, !description.isEmpty {
|
|
|
|
Text(description)
|
|
|
|
.font(.scaledBody)
|
|
|
|
.foregroundColor(.gray)
|
|
|
|
.lineLimit(3)
|
|
|
|
}
|
|
|
|
Text(url.host() ?? url.absoluteString)
|
|
|
|
.font(.scaledFootnote)
|
|
|
|
.foregroundColor(theme.tintColor)
|
|
|
|
.lineLimit(1)
|
2022-12-19 16:18:16 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
Spacer()
|
|
|
|
}.padding(16)
|
2023-01-19 06:45:37 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
.frame(maxWidth: maxWidth)
|
|
|
|
.fixedSize(horizontal: false, vertical: true)
|
2023-09-12 13:55:11 +00:00
|
|
|
.background(.ultraThinMaterial)
|
2023-07-17 17:13:36 +00:00
|
|
|
.cornerRadius(16)
|
|
|
|
.overlay(
|
|
|
|
RoundedRectangle(cornerRadius: 16)
|
|
|
|
.stroke(.gray.opacity(0.35), lineWidth: 1)
|
|
|
|
)
|
|
|
|
.contextMenu {
|
|
|
|
ShareLink(item: url) {
|
|
|
|
Label("status.card.share", systemImage: "square.and.arrow.up")
|
|
|
|
}
|
|
|
|
Button { openURL(url) } label: {
|
|
|
|
Label("status.action.view-in-browser", systemImage: "safari")
|
|
|
|
}
|
|
|
|
Divider()
|
|
|
|
Button {
|
|
|
|
UIPasteboard.general.url = url
|
|
|
|
} label: {
|
|
|
|
Label("status.card.copy", systemImage: "doc.on.doc")
|
|
|
|
}
|
2023-01-19 06:45:37 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
.accessibilityElement(children: .combine)
|
|
|
|
.accessibilityAddTraits(.isLink)
|
|
|
|
.accessibilityRemoveTraits(.isStaticText)
|
2023-01-19 06:45:37 +00:00
|
|
|
}
|
2022-12-19 16:18:16 +00:00
|
|
|
}
|
2023-07-17 17:13:36 +00:00
|
|
|
.buttonStyle(.plain)
|
2022-12-19 16:18:16 +00:00
|
|
|
}
|
|
|
|
}
|