AppStore Link Preview (#1756)
* Custom layout for App Store links * generalize the logic to include links known to be associated with square icons - such as Apple Music and Spotify
This commit is contained in:
parent
d755396119
commit
2145bd5971
|
@ -46,44 +46,12 @@ public struct StatusRowCardView: View {
|
|||
} label: {
|
||||
if let title = card.title, let url = URL(string: card.url) {
|
||||
VStack(alignment: .leading) {
|
||||
if let imageURL = card.image, !isInCaptureMode {
|
||||
LazyResizableImage(url: imageURL) { state, proxy in
|
||||
let width = imageWidthFor(proxy: proxy)
|
||||
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)
|
||||
}
|
||||
}
|
||||
// This image is decorative
|
||||
.accessibilityHidden(true)
|
||||
.frame(height: imageHeight)
|
||||
let sitesWithIcons = [ "apps.apple.com", "music.apple.com", "open.spotify.com" ]
|
||||
if let host = url.host(), sitesWithIcons.contains(host) {
|
||||
iconLinkPreview(title, url)
|
||||
} else {
|
||||
defaultLinkPreview(title, url)
|
||||
}
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.font(.scaledHeadline)
|
||||
.lineLimit(3)
|
||||
if let description = card.description, !description.isEmpty {
|
||||
Text(description)
|
||||
.font(.scaledBody)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(3)
|
||||
}
|
||||
Text(url.host() ?? url.absoluteString)
|
||||
.font(.scaledFootnote)
|
||||
.foregroundColor(theme.tintColor)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Spacer()
|
||||
}.padding(16)
|
||||
}
|
||||
.frame(maxWidth: maxWidth)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
@ -114,4 +82,89 @@ public struct StatusRowCardView: View {
|
|||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func defaultLinkPreview(_ title: String, _ url: URL) -> some View {
|
||||
Group {
|
||||
if let imageURL = card.image, !isInCaptureMode {
|
||||
LazyResizableImage(url: imageURL) { state, proxy in
|
||||
let width = imageWidthFor(proxy: proxy)
|
||||
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)
|
||||
}
|
||||
}
|
||||
// This image is decorative
|
||||
.accessibilityHidden(true)
|
||||
.frame(height: imageHeight)
|
||||
}
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.font(.scaledHeadline)
|
||||
.lineLimit(3)
|
||||
if let description = card.description, !description.isEmpty {
|
||||
Text(description)
|
||||
.font(.scaledBody)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(3)
|
||||
}
|
||||
Text(url.host() ?? url.absoluteString)
|
||||
.font(.scaledFootnote)
|
||||
.foregroundColor(theme.tintColor)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Spacer()
|
||||
}.padding(16)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func iconLinkPreview(_ title: String, _ url: URL) -> some View {
|
||||
// ..where the image is known to be a square icon
|
||||
HStack {
|
||||
if let imageURL = card.image, !isInCaptureMode {
|
||||
LazyResizableImage(url: imageURL) { state, proxy in
|
||||
if let image = state.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: imageHeight, height: imageHeight)
|
||||
.clipped()
|
||||
} else if state.isLoading {
|
||||
Rectangle()
|
||||
.fill(Color.gray)
|
||||
.frame(width: imageHeight, height: imageHeight)
|
||||
}
|
||||
}
|
||||
// This image is decorative
|
||||
.accessibilityHidden(true)
|
||||
.frame(width: imageHeight, height: imageHeight)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.font(.scaledHeadline)
|
||||
.lineLimit(3)
|
||||
if let description = card.description, !description.isEmpty {
|
||||
Text(description)
|
||||
.font(.scaledBody)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(3)
|
||||
}
|
||||
Text(url.host() ?? url.absoluteString)
|
||||
.font(.scaledFootnote)
|
||||
.foregroundColor(theme.tintColor)
|
||||
.lineLimit(1)
|
||||
}.padding(16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue