Tusker/Tusker/HTMLConverter.swift

77 lines
2.6 KiB
Swift

//
// HTMLConverter.swift
// Tusker
//
// Created by Shadowfacts on 12/3/22.
// Copyright © 2022 Shadowfacts. All rights reserved.
//
import UIKit
import HTMLStreamer
import WebURL
import WebURLFoundationExtras
class HTMLConverter {
static let defaultFont = UIFont.systemFont(ofSize: 17)
static let defaultMonospaceFont = UIFont.monospacedSystemFont(ofSize: 17, weight: .regular)
static let defaultColor = UIColor.label
static let defaultParagraphStyle: NSParagraphStyle = {
let style = NSMutableParagraphStyle()
// 2 points is enough that it doesn't make things look weirdly spaced out, but leaves a slight gap when there are multiple lines of emojis
style.lineSpacing = 2
return style
}()
private let converter: AttributedStringConverter<Callbacks>
init(font: UIFont, monospaceFont: UIFont, fontMetrics: UIFontMetrics, color: UIColor, paragraphStyle: NSParagraphStyle) {
let config = AttributedStringConverterConfiguration(
font: font,
monospaceFont: monospaceFont,
fontMetrics: fontMetrics,
color: color,
paragraphStyle: paragraphStyle
)
self.converter = AttributedStringConverter(configuration: config)
}
func convert(_ html: String) -> NSAttributedString {
converter.convert(html: html)
}
}
extension HTMLConverter {
// note: this is duplicated in NotificationExtension
struct Callbacks: HTMLConversionCallbacks {
static func makeURL(string: String) -> URL? {
// Converting WebURL to URL is a small but non-trivial expense (since it works by
// serializing the WebURL as a string and then having Foundation parse it again),
// so, if available, use the system parser which doesn't require another round trip.
if #available(iOS 16.0, macOS 13.0, *),
let url = try? URL.ParseStrategy().parse(string) {
url
} else if let web = WebURL(string),
let url = URL(web) {
url
} else {
URL(string: string)
}
}
static func elementAction(name: String, attributes: [Attribute]) -> ElementAction {
guard name == "span" else {
return .default
}
let clazz = attributes.attributeValue(for: "class")
if clazz == "invisible" {
return .skip
} else if clazz == "ellipsis" {
return .append("")
} else {
return .default
}
}
}
}