import UIKit // MARK: - Public Reader Commands extension RDEPUBReaderController { /// 重新加载书籍,重置所有状态并重新解析 EPUB public func reloadBook() { runtime.reloadBook() } /// 跳转到指定阅读位置 /// - Parameter location: 目标阅读位置 public func go(to location: RDEPUBLocation) { guard publication != nil else { return } _ = runtime.go(to: location) } /// 跳转到指定页码 /// - Parameters: /// - pageNumber: 目标页码(从 1 开始) /// - animated: 是否动画过渡 /// - Returns: 是否跳转成功 @discardableResult public func go(toPageNumber pageNumber: Int, animated: Bool = false) -> Bool { runtime.go(toPageNumber: pageNumber, animated: animated) } /// 清除当前文本选中状态 public func clearSelection() { runtime.clearSelection() } public func bookmark(withID id: String) -> RDEPUBBookmark? { runtime.bookmark(withID: id) } public func highlight(withID id: String) -> RDEPUBHighlight? { runtime.highlight(withID: id) } public func nativeTextSemanticSummary() -> String? { guard let textBook, let page = textBook.page(at: max(readerView.currentPage + 1, 1)) ?? textBook.pages.first else { return nil } let metadata = page.metadata var parts = [ "page \(page.absolutePageIndex + 1)", "break \(metadata.breakReason.rawValue)", metadata.blockKinds.isEmpty ? nil : "block kinds [\(metadata.blockKinds.map(\.rawValue).joined(separator: ","))]", metadata.semanticHints.isEmpty ? nil : "hints [\(metadata.semanticHints.map(\.rawValue).joined(separator: ","))]", metadata.attachmentPlacements.isEmpty ? nil : "placements [\(metadata.attachmentPlacements.map(\.rawValue).joined(separator: ","))]" ].compactMap { $0 } if let firstDiagnostic = metadata.diagnostics.first { parts.append(firstDiagnostic) } return parts.joined(separator: " · ") } /// 添加高亮标注,从当前选中文本或指定选区创建 /// - Parameters: /// - selection: 文本选区,默认使用 currentSelection /// - color: 高亮颜色(CSS 格式),默认黄色 /// - note: 可选批注文字 /// - Returns: 创建的高亮对象,重复时返回 nil @discardableResult public func addHighlight( from selection: RDEPUBSelection? = nil, color: String = "#F8E16C", note: String? = nil ) -> RDEPUBHighlight? { runtime.addHighlight(from: selection, color: color, note: note) } @discardableResult public func addAnnotation( from selection: RDEPUBSelection? = nil, style: RDEPUBHighlightStyle, color: String = "#F8E16C", note: String? = nil ) -> RDEPUBHighlight? { runtime.addAnnotation(from: selection, style: style, color: color, note: note) } @discardableResult public func upsertHighlight(_ highlight: RDEPUBHighlight) -> RDEPUBHighlight? { runtime.upsertHighlight(highlight) } @discardableResult public func removeHighlight(id: String) -> RDEPUBHighlight? { runtime.removeHighlight(id: id) } @discardableResult public func updateHighlightNote(id: String, note: String?) -> RDEPUBHighlight? { runtime.updateHighlightNote(id: id, note: note) } @discardableResult public func go(toHighlightID id: String, animated: Bool = true) -> Bool { runtime.go(toHighlightID: id, animated: animated) } public func removeAllHighlights() { runtime.removeAllHighlights() } @discardableResult public func go(toTableOfContentsItem item: EPUBTableOfContentsItem, animated: Bool = true) -> Bool { go(toTableOfContentsHref: item.href, animated: animated) } @discardableResult public func go(toTableOfContentsItem item: RDEPUBReaderTableOfContentsItem, animated: Bool = true) -> Bool { go(toTableOfContentsHref: item.href, animated: animated) } @discardableResult public func go(toTableOfContentsHref href: String, animated: Bool = true) -> Bool { guard publication != nil else { return false } let components = href.components(separatedBy: "#") let baseHref = components.first ?? href let fragment = components.count > 1 ? components[1] : nil let location = RDEPUBLocation( bookIdentifier: currentBookIdentifier, href: baseHref, progression: 0, fragment: fragment ) return restoreReadingLocation(location, animated: animated) } @discardableResult public func addBookmark(note: String? = nil) -> RDEPUBBookmark? { runtime.addBookmark(note: note) } @discardableResult public func toggleBookmark(note: String? = nil) -> RDEPUBBookmark? { runtime.toggleBookmark(note: note) } @discardableResult public func removeBookmark(id: String) -> RDEPUBBookmark? { runtime.removeBookmark(id: id) } @discardableResult public func go(toBookmarkID id: String, animated: Bool = true) -> Bool { runtime.go(toBookmarkID: id, animated: animated) } /// 执行全文搜索,自动跳转到第一个匹配项 /// - Parameter keyword: 搜索关键词,空字符串会清除搜索 public func search(keyword: String) { runtime.search(keyword: keyword) } @discardableResult public func searchNext() -> Bool { runtime.searchNext() } @discardableResult public func searchPrevious() -> Bool { runtime.searchPrevious() } public func clearSearch() { runtime.clearSearch() } }