IceCubesApp/Packages/Status/Sources/Status/Row/Subviews/StatusRowCardView.swift

122 lines
3.5 KiB
Swift
Raw Normal View History

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
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
let card: Card
2023-01-17 10:36:01 +00:00
public init(card: Card) {
self.card = card
}
2023-02-22 18:09:39 +00:00
private var maxWidth: CGFloat? {
if theme.statusDisplayStyle == .medium {
return 300
}
return nil
}
2023-02-22 18:09:39 +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
private var imageHeight: CGFloat {
if theme.statusDisplayStyle == .medium {
return 100
}
return 200
}
2023-01-17 10:36:01 +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
}
}