frenzy-ios/Reader/Screens/Read/ReadViewController.swift

126 lines
3.9 KiB
Swift
Raw Normal View History

2022-01-10 04:38:44 +00:00
//
// ReadViewController.swift
// Reader
//
// Created by Shadowfacts on 1/9/22.
//
import UIKit
import WebKit
import HTMLEntities
class ReadViewController: UIViewController {
private static let publishedFormatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
f.timeStyle = .medium
return f
}()
let fervorController: FervorController
let item: Item
override var prefersStatusBarHidden: Bool {
navigationController?.isNavigationBarHidden ?? false
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
.slide
}
init(item: Item, fervorController: FervorController) {
self.fervorController = fervorController
self.item = item
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.largeTitleDisplayMode = .never
view.backgroundColor = .appBackground
let webView = WKWebView()
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
if let content = itemContentHTML() {
// todo: using the bundle url is the only way to get the stylesheet to load, but feels wrong
// will break, e.g., images with relative urls
webView.loadHTMLString(content, baseURL: Bundle.main.bundleURL)
}
view.addSubview(webView)
NSLayoutConstraint.activate([
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
private func itemContentHTML() -> String? {
guard let content = item.content else {
return nil
}
var info = ""
if let title = item.title, !title.isEmpty {
info += "<h1 id=\"item-title\">"
if let url = item.url {
info += "<a href=\"\(url.absoluteString)\">"
}
info += title.htmlEscape()
if item.url != nil {
info += "</a>"
}
info += "</h1>"
}
if let feedTitle = item.feed!.title, !feedTitle.isEmpty {
info += "<h2 id=\"item-feed-title\">\(feedTitle.htmlEscape())</h2>"
}
if let author = item.author, !author.isEmpty {
info += "<h3 id=\"item-author\">\(author)</h3>"
}
if let published = item.published {
let formatted = ReadViewController.publishedFormatter.string(from: published)
info += "<h3 id=\"item-published\">\(formatted)</h3>"
}
return """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="\(Bundle.main.url(forResource: "read", withExtension: "css")!.absoluteString)" />
</head>
<body>
<div id="item-info">
\(info)
</div>
<div id="item-content">
\(content)
</div>
</body>
</html>
"""
}
}
extension ReadViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
let url = navigationAction.request.url!
if url == Bundle.main.bundleURL {
return .allow
}
return .cancel
}
}