1
Fork 0

Parse content at profile load to allow for better text layout

This commit is contained in:
redstrate 2020-06-04 08:00:35 -04:00
parent c42537d885
commit c76c6fd0f1
3 changed files with 68 additions and 39 deletions

View file

@ -54,6 +54,11 @@ struct Post: Decodable, Identifiable {
} }
} }
struct ParsedPostContainer {
let post: Post
let contentAttributed: NSAttributedString
}
let mediaURL = "https://homepages.cae.wisc.edu/~ece533/images/airplane.png" let mediaURL = "https://homepages.cae.wisc.edu/~ece533/images/airplane.png"
let testMedia = Media(id: 0, let testMedia = Media(id: 0,

View file

@ -7,44 +7,60 @@ extension String {
} }
} }
/// A custom view to use NSAttributedString in SwiftUI final class AttributedTextComponent: UIViewRepresentable {
struct AttributedText: UIViewRepresentable { let string: NSAttributedString
init(_ string: NSAttributedString) {
self.string = string
}
public func makeUIView(context: UIViewRepresentableContext<AttributedTextComponent>) -> UILabel {
UILabel()
}
func updateUIView(_ uiView: UILabel, context: Context) { func updateUIView(_ uiView: UILabel, context: Context) {
uiView.backgroundColor = .clear
uiView.numberOfLines = 0
uiView.lineBreakMode = .byWordWrapping
uiView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
uiView.attributedText = string
}
} }
let html: String struct AttributedText: View {
let html: NSAttributedString
let component: AttributedTextComponent
init(_ html: String) { @State var height: CGFloat = 0.0
init(_ html: NSAttributedString) {
self.html = html self.html = html
self.component = AttributedTextComponent(html)
} }
public func makeUIView(context: UIViewRepresentableContext<AttributedText>) -> UILabel { var body: some View {
let textView = UILabel() component.onAppear {
textView.backgroundColor = .clear let label = UILabel()
textView.lineBreakMode = .byWordWrapping
textView.numberOfLines = 0
textView.lineBreakMode = .byWordWrapping
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
DispatchQueue.main.async { label.numberOfLines = 0
let data = Data(self.html.utf8) label.lineBreakMode = .byWordWrapping
if let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) { label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
textView.attributedText = attributedString
}
}
return textView label.attributedText = self.html
label.sizeToFit()
self.height = label.frame.height + 15.0 // for padding
}.frame(minWidth: 0.0, maxWidth: .infinity, minHeight: 0.0, maxHeight: height)
} }
} }
struct PostView: View { struct PostView: View {
let post: Post let post: ParsedPostContainer
var body: some View { var body: some View {
VStack { VStack {
HStack { HStack {
RemoteImage(type: .url(URL(string: post.avatarUrl.encodeUrl()!)!), errorView: { error in RemoteImage(type: .url(URL(string: post.post.avatarUrl.encodeUrl()!)!), errorView: { error in
Text(error.localizedDescription) Text(error.localizedDescription)
}, imageView: { image in }, imageView: { image in
image image
@ -55,12 +71,12 @@ struct PostView: View {
}).frame(width: 50.0, height: 50.0).padding(.leading) }).frame(width: 50.0, height: 50.0).padding(.leading)
VStack(alignment: .leading) { VStack(alignment: .leading) {
if post.isReblogged() { if post.post.isReblogged() {
Text(post.username + " reblogged from " + post.originalUsername!).foregroundColor(.gray) Text(post.post.username + " reblogged from " + post.post.originalUsername!).foregroundColor(.gray)
} }
if post.getTitle() != nil { if post.post.getTitle() != nil {
Text(post.getTitle()!) Text(post.post.getTitle()!)
} }
} }
@ -68,7 +84,7 @@ struct PostView: View {
}.frame(maxWidth: .infinity) }.frame(maxWidth: .infinity)
VStack { VStack {
ForEach(post.media) { media in ForEach(post.post.media) { media in
if !media.url.isEmpty { if !media.url.isEmpty {
VStack { VStack {
RemoteImage(type: .url(URL(string: media.url.encodeUrl()!)!), errorView: { error in RemoteImage(type: .url(URL(string: media.url.encodeUrl()!)!), errorView: { error in
@ -83,15 +99,15 @@ struct PostView: View {
} }
} }
} }
AttributedText(post.getContent()).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
} }
AttributedText(post.contentAttributed)
}.frame(maxWidth: .infinity) }.frame(maxWidth: .infinity)
} }
} }
struct PostView_Previews: PreviewProvider { struct PostView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
return PostView(post: fooPost) return PostView(post: ParsedPostContainer(post: fooPost, contentAttributed: NSAttributedString()))
} }
} }

View file

@ -3,11 +3,11 @@ import SwiftUI
struct ProfileView: View { struct ProfileView: View {
let username: String let username: String
@State var posts: [Post] = [] @State var posts: [ParsedPostContainer] = []
var body: some View { var body: some View {
VStack { VStack {
List(posts) { post in List(posts, id: \.post.id) { post in
PostView(post: post) PostView(post: post)
} }
}.navigationBarTitle(username + "'s Feed").onAppear { }.navigationBarTitle(username + "'s Feed").onAppear {
@ -25,8 +25,15 @@ struct ProfileView: View {
let decodedPosts = try decoder.decode(Posts.self, from: jsonData) let decodedPosts = try decoder.decode(Posts.self, from: jsonData)
var postArray = [ParsedPostContainer]()
for post in decodedPosts.posts {
let container = ParsedPostContainer(post: post, contentAttributed: (try? NSAttributedString(data: post.getContent().data(using: .utf8)!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil))!)
postArray.append(container)
}
DispatchQueue.main.sync { DispatchQueue.main.sync {
self.posts = decodedPosts.posts self.posts = postArray
} }
} }
} catch { } catch {
@ -39,6 +46,7 @@ struct ProfileView: View {
struct ProfileView_Previews: PreviewProvider { struct ProfileView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
return ProfileView(username: "foobar", posts: [fooPost, fooPostReblog]) //return ProfileView(username: "foobar", posts: [fooPost, fooPostReblog])
Text("hello, world!")
} }
} }