* iOS Share extension * Add Fastlane steps for iOS Share Extension * new multi file layout * Add recent label * Refactor code & identation * ux feedback * downsample images * remove options horizontal padding
119 lines
3.4 KiB
Swift
119 lines
3.4 KiB
Swift
//
|
|
// LinkPreview.swift
|
|
// MattermostShare
|
|
//
|
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
//
|
|
|
|
import SwiftUI
|
|
import OpenGraph
|
|
|
|
struct OpenGraphData {
|
|
var title: String?
|
|
var link: String
|
|
var type: String?
|
|
var siteName: String?
|
|
var description: String?
|
|
var imageURL: String?
|
|
var error: Error?
|
|
}
|
|
|
|
struct LinkPreview: View {
|
|
@Binding var link: String
|
|
@Binding var message: String
|
|
@State private var data: OpenGraphData = OpenGraphData(link: "")
|
|
|
|
var body: some View {
|
|
let borderColor = Color.theme.centerChannelColor.opacity(0.16)
|
|
VStack {
|
|
if (data.error == nil) {
|
|
ZStack {
|
|
HStack (alignment: .top, spacing: 10) {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(data.title ?? "")
|
|
.foregroundColor(Color.theme.linkColor)
|
|
.multilineTextAlignment(.leading)
|
|
.lineLimit(2)
|
|
.font(Font.custom("OpenSans-SemiBold", size: 16))
|
|
|
|
Text(verbatim: data.link)
|
|
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
|
.multilineTextAlignment(.leading)
|
|
.lineLimit(2)
|
|
.font(Font.custom("OpenSans", size: 12))
|
|
}
|
|
Spacer()
|
|
if (data.imageURL != nil) {
|
|
VStack {
|
|
AsyncImage(url: URL(string: data.imageURL!)) { phase in
|
|
if let image = phase.image {
|
|
image
|
|
.resizable()
|
|
.scaledToFill()
|
|
.frame(width: 72, height: 72)
|
|
} else if phase.error != nil {
|
|
FontIcon.text(
|
|
.compassIcons(code: .brokenImage),
|
|
fontsize: 24
|
|
)
|
|
} else {
|
|
ProgressView()
|
|
}
|
|
}
|
|
.cornerRadius(4)
|
|
.frame(width: 72, height: 72)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 4)
|
|
.stroke(borderColor, lineWidth: 1)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
.padding(.horizontal, 10)
|
|
}
|
|
.frame(minWidth: 0,
|
|
maxWidth: .infinity,
|
|
minHeight: 0,
|
|
maxHeight: 96,
|
|
alignment: .leading)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 4)
|
|
.stroke(borderColor, lineWidth: 1)
|
|
.shadow(color: borderColor, radius: 3, x: 0, y: 2)
|
|
)
|
|
}
|
|
}
|
|
.task (id: link) {
|
|
await fetchData()
|
|
}
|
|
}
|
|
|
|
private func fetchData() async {
|
|
do {
|
|
guard let url = URL(string: link) else {return}
|
|
|
|
let openGraph = try await OpenGraph.fetch(url: url)
|
|
var imageUrl = openGraph[.image];
|
|
if (imageUrl != nil) {
|
|
var comps = URLComponents(string: imageUrl!)!
|
|
comps.scheme = "https"
|
|
imageUrl = comps.string
|
|
}
|
|
let data = OpenGraphData(
|
|
title: openGraph[.title],
|
|
link: openGraph[.url] ?? link,
|
|
type: openGraph[.type],
|
|
siteName: openGraph[.siteName],
|
|
description: openGraph[.description],
|
|
imageURL: imageUrl,
|
|
error: nil
|
|
)
|
|
self.data = data
|
|
} catch {
|
|
self.data.error = error
|
|
message = link
|
|
link = ""
|
|
}
|
|
}
|
|
}
|