import UIKit public final class RDURLReaderController: UIViewController { private let bookURL: URL private let epubConfiguration: RDEPUBReaderConfiguration private var embeddedController: UIViewController? public init( bookURL: URL, epubConfiguration: RDEPUBReaderConfiguration = RDEPUBReaderConfiguration() ) { self.bookURL = bookURL self.epubConfiguration = epubConfiguration super.init(nibName: nil, bundle: nil) } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } public override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground title = bookURL.deletingPathExtension().lastPathComponent embedReaderController() } private func embedReaderController() { let controller: UIViewController if bookURL.pathExtension.lowercased() == "epub" { controller = RDEPUBReaderController( epubURL: bookURL, configuration: epubConfiguration ) } else { let bookIdentifier = bookURL.lastPathComponent let bookTitle = bookURL.deletingPathExtension().lastPathComponent let pageSize = currentTextPageSize() let renderStyle = currentTextRenderStyle() let builder = RDPlainTextBookBuilder() if let textBook = try? builder.build(textFileURL: bookURL, pageSize: pageSize, style: renderStyle) { controller = RDEPUBReaderController( textBook: textBook, bookIdentifier: bookIdentifier, title: bookTitle, textFileURL: bookURL, configuration: epubConfiguration ) } else { // 分页失败时回退到纯文本展示 let fallback = UIViewController() let textView = UITextView() textView.isEditable = false textView.text = rd_decodeTextFile(url: bookURL) fallback.view = textView controller = fallback } } embeddedController = controller addChild(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(controller.view) NSLayoutConstraint.activate([ controller.view.topAnchor.constraint(equalTo: view.topAnchor), controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) controller.didMove(toParent: self) } private func currentTextPageSize() -> CGSize { let viewportSize = UIScreen.main.bounds.size let insets = epubConfiguration.reflowableContentInsets return CGSize( width: max(viewportSize.width - insets.left - insets.right, 1), height: max(viewportSize.height - insets.top - insets.bottom, 1) ) } private func currentTextRenderStyle() -> RDEPUBTextRenderStyle { let font = UIFont.systemFont(ofSize: epubConfiguration.fontSize) let lineSpacing = max(font.lineHeight * (epubConfiguration.lineHeightMultiple - 1), 4) return RDEPUBTextRenderStyle( font: font, lineSpacing: lineSpacing, textColor: epubConfiguration.theme.contentTextColor, backgroundColor: epubConfiguration.theme.contentBackgroundColor ) } private func rd_decodeTextFile(url: URL) -> String { if let content = try? NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue) as String { return content } if let content = try? NSString(contentsOf: url, encoding: 0x80000632) as String { return content } if let content = try? NSString(contentsOf: url, encoding: 0x80000631) as String { return content } return "" } }