Tusker/Tusker/HTMLConverter.swift

71 lines
2.5 KiB
Swift
Raw Normal View History

//
// HTMLConverter.swift
// Tusker
//
// Created by Shadowfacts on 12/3/22.
// Copyright © 2022 Shadowfacts. All rights reserved.
//
import UIKit
2023-12-23 01:44:46 +00:00
import HTMLStreamer
import WebURL
import WebURLFoundationExtras
2023-12-23 01:44:46 +00:00
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>
2023-12-23 01:44:46 +00:00
init(font: UIFont, monospaceFont: UIFont, color: UIColor, paragraphStyle: NSParagraphStyle) {
let config = AttributedStringConverterConfiguration(font: font, monospaceFont: monospaceFont, color: color, paragraphStyle: paragraphStyle)
self.converter = AttributedStringConverter(configuration: config)
}
func convert(_ html: String) -> NSAttributedString {
2023-12-23 01:44:46 +00:00
converter.convert(html: html)
}
2023-12-23 01:44:46 +00:00
}
extension HTMLConverter {
2024-04-11 16:44:41 +00:00
// note: this is duplicated in NotificationExtension
2023-12-23 01:44:46 +00:00
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 {
2023-12-23 01:44:46 +00:00
URL(string: string)
}
2023-12-23 01:44:46 +00:00
}
static func elementAction(name: String, attributes: [Attribute]) -> ElementAction {
guard name == "span" else {
return .default
}
2023-12-23 01:44:46 +00:00
let clazz = attributes.attributeValue(for: "class")
if clazz == "invisible" {
return .skip
} else if clazz == "ellipsis" {
return .append("")
} else {
2023-12-23 01:44:46 +00:00
return .default
}
}
}
}