mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-24 06:48:10 +00:00
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
1 changed files with 90 additions and 37 deletions
|
@ -46,6 +46,46 @@ public struct StatusRowCardView: View {
|
||||||
} label: {
|
} label: {
|
||||||
if let title = card.title, let url = URL(string: card.url) {
|
if let title = card.title, let url = URL(string: card.url) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: maxWidth)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
.background(theme.secondaryBackgroundColor)
|
||||||
|
.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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.accessibilityElement(children: .combine)
|
||||||
|
.accessibilityAddTraits(.isLink)
|
||||||
|
.accessibilityRemoveTraits(.isStaticText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private func defaultLinkPreview(_ title: String, _ url: URL) -> some View {
|
||||||
|
Group {
|
||||||
if let imageURL = card.image, !isInCaptureMode {
|
if let imageURL = card.image, !isInCaptureMode {
|
||||||
LazyResizableImage(url: imageURL) { state, proxy in
|
LazyResizableImage(url: imageURL) { state, proxy in
|
||||||
let width = imageWidthFor(proxy: proxy)
|
let width = imageWidthFor(proxy: proxy)
|
||||||
|
@ -85,33 +125,46 @@ public struct StatusRowCardView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
}.padding(16)
|
}.padding(16)
|
||||||
}
|
}
|
||||||
.frame(maxWidth: maxWidth)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.background(theme.secondaryBackgroundColor)
|
|
||||||
.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")
|
@MainActor
|
||||||
}
|
private func iconLinkPreview(_ title: String, _ url: URL) -> some View {
|
||||||
Divider()
|
// ..where the image is known to be a square icon
|
||||||
Button {
|
HStack {
|
||||||
UIPasteboard.general.url = url
|
if let imageURL = card.image, !isInCaptureMode {
|
||||||
} label: {
|
LazyResizableImage(url: imageURL) { state, proxy in
|
||||||
Label("status.card.copy", systemImage: "doc.on.doc")
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.accessibilityElement(children: .combine)
|
// This image is decorative
|
||||||
.accessibilityAddTraits(.isLink)
|
.accessibilityHidden(true)
|
||||||
.accessibilityRemoveTraits(.isStaticText)
|
.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)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue