feat(epub): align wxread css and overlay pagination behavior
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// RDEPUBWebView 的搜索高亮扩展
|
||||
// 从当前渲染请求中提取搜索展示信息,生成搜索高亮脚本并注入到 WebView 中执行。
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
|
||||
extension RDEPUBWebView {
|
||||
@@ -31,7 +32,107 @@ extension RDEPUBWebView {
|
||||
if let error {
|
||||
self.delegate?.epubWebView(self, didLogJavaScriptError: error.localizedDescription)
|
||||
}
|
||||
self.refreshNativeDecorationsIfNeeded(completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
func refreshNativeDecorationsIfNeeded(completion: (() -> Void)? = nil) {
|
||||
guard let webView else {
|
||||
onDecorationsResolved?([])
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
|
||||
webView.evaluateJavaScript(RDEPUBJavaScriptBridge.resolveDecorationsScript()) { [weak self] result, error in
|
||||
guard let self else {
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
if let error {
|
||||
self.delegate?.epubWebView(self, didLogJavaScriptError: error.localizedDescription)
|
||||
self.onDecorationsResolved?([])
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
|
||||
let decorations = self.nativeDecorations(from: result)
|
||||
self.onDecorationsResolved?(decorations)
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
private func nativeDecorations(from result: Any?) -> [RDEPUBTextOverlayDecoration] {
|
||||
guard let payload = result as? [String: Any] else { return [] }
|
||||
|
||||
let highlightDecorations = decorationList(
|
||||
from: payload["highlights"] as? [[String: Any]],
|
||||
defaultColor: overlayColor(hex: "#F8E16C", alpha: 0.45) ?? UIColor(red: 248 / 255, green: 225 / 255, blue: 108 / 255, alpha: 0.45)
|
||||
)
|
||||
let searchDecorations = decorationList(
|
||||
from: payload["search"] as? [[String: Any]],
|
||||
defaultColor: UIColor(red: 248 / 255, green: 225 / 255, blue: 108 / 255, alpha: 0.55)
|
||||
)
|
||||
return highlightDecorations + searchDecorations
|
||||
}
|
||||
|
||||
private func decorationList(
|
||||
from items: [[String: Any]]?,
|
||||
defaultColor: UIColor
|
||||
) -> [RDEPUBTextOverlayDecoration] {
|
||||
guard let items else { return [] }
|
||||
|
||||
return items.enumerated().compactMap { index, item -> RDEPUBTextOverlayDecoration? in
|
||||
guard let kindString = item["kind"] as? String,
|
||||
let kind = RDEPUBTextOverlayDecoration.Kind(rawValue: kindString),
|
||||
let rectPayloads = item["rects"] as? [[String: Any]] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let rects = rectPayloads.compactMap { rectPayload -> CGRect? in
|
||||
guard let x = (rectPayload["x"] as? NSNumber)?.doubleValue,
|
||||
let y = (rectPayload["y"] as? NSNumber)?.doubleValue,
|
||||
let width = (rectPayload["width"] as? NSNumber)?.doubleValue,
|
||||
let height = (rectPayload["height"] as? NSNumber)?.doubleValue else {
|
||||
return nil
|
||||
}
|
||||
return CGRect(x: x, y: y, width: width, height: height)
|
||||
}
|
||||
guard !rects.isEmpty else { return nil }
|
||||
|
||||
let color: UIColor
|
||||
switch kind {
|
||||
case .underline:
|
||||
let hex = item["color"] as? String ?? "#F8E16C"
|
||||
color = overlayColor(hex: hex, alpha: 1) ?? defaultColor
|
||||
case .activeSearch:
|
||||
color = UIColor(red: 255 / 255, green: 159 / 255, blue: 67 / 255, alpha: 0.75)
|
||||
case .search:
|
||||
color = UIColor(red: 248 / 255, green: 225 / 255, blue: 108 / 255, alpha: 0.55)
|
||||
case .highlight:
|
||||
let hex = item["color"] as? String ?? "#F8E16C"
|
||||
color = overlayColor(hex: hex, alpha: 0.45) ?? defaultColor
|
||||
case .selection, .locate:
|
||||
color = defaultColor
|
||||
}
|
||||
|
||||
return RDEPUBTextOverlayDecoration(
|
||||
kind: kind,
|
||||
absoluteRange: NSRange(location: index, length: 1),
|
||||
rects: rects,
|
||||
color: color
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func overlayColor(hex: String, alpha: CGFloat) -> UIColor? {
|
||||
var value = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
value = value.replacingOccurrences(of: "#", with: "")
|
||||
guard value.count == 6, let hexValue = Int(value, radix: 16) else { return nil }
|
||||
return UIColor(
|
||||
red: CGFloat((hexValue >> 16) & 0xFF) / 255,
|
||||
green: CGFloat((hexValue >> 8) & 0xFF) / 255,
|
||||
blue: CGFloat(hexValue & 0xFF) / 255,
|
||||
alpha: alpha
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user