Fix reader interaction and web resource handling
This commit is contained in:
@@ -6,6 +6,10 @@ extension RDReaderView {
|
||||
func tapCenter() {
|
||||
refreshToolViewsFromProviderIfNeeded()
|
||||
isShowToolView = !isShowToolView
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.tapCenter",
|
||||
"toggle toolView visible=\(isShowToolView) top=\(RDReaderTapDebug.describe(topToolView)) bottom=\(RDReaderTapDebug.describe(bottomToolView))"
|
||||
)
|
||||
if isShowToolView {
|
||||
if let topToolView = topToolView {
|
||||
installToolViewIfNeeded(topToolView, position: .top)
|
||||
@@ -27,6 +31,7 @@ extension RDReaderView {
|
||||
|
||||
collectionView.isUserInteractionEnabled = false
|
||||
pageViewController.view.isUserInteractionEnabled = false
|
||||
RDReaderTapDebug.log("ReaderView.tapCenter", "disabled collectionView/pageViewController interaction while toolView is visible")
|
||||
} else {
|
||||
if let topToolView = topToolView {
|
||||
UIView.animate(withDuration: toolViewAnimationDuration, animations: {
|
||||
@@ -46,6 +51,7 @@ extension RDReaderView {
|
||||
|
||||
collectionView.isUserInteractionEnabled = true
|
||||
pageViewController.view.isUserInteractionEnabled = true
|
||||
RDReaderTapDebug.log("ReaderView.tapCenter", "re-enabled collectionView/pageViewController interaction after hiding toolView")
|
||||
}
|
||||
onToolViewVisibilityChanged?(isShowToolView)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,53 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
enum RDReaderTapDebug {
|
||||
|
||||
private static let enabledArguments: Set<String> = [
|
||||
"--demo-tap-debug",
|
||||
"--demo-reader-interaction-debug"
|
||||
]
|
||||
|
||||
static var isEnabled: Bool {
|
||||
#if DEBUG
|
||||
return true
|
||||
#else
|
||||
let arguments = ProcessInfo.processInfo.arguments
|
||||
if arguments.contains(where: { enabledArguments.contains($0) }) {
|
||||
return true
|
||||
}
|
||||
|
||||
let environment = ProcessInfo.processInfo.environment
|
||||
return environment["RDREADER_TAP_DEBUG"] == "1"
|
||||
#endif
|
||||
}
|
||||
|
||||
static func log(_ scope: String, _ message: String) {
|
||||
guard isEnabled else { return }
|
||||
let threadRole = Thread.isMainThread ? "main" : "bg"
|
||||
let queueLabel = String(validatingUTF8: __dispatch_queue_get_label(nil)) ?? "unknown"
|
||||
print("[RDReaderTap][\(scope)][\(threadRole)][queue=\(queueLabel)] \(message)")
|
||||
}
|
||||
|
||||
static func describe(_ point: CGPoint) -> String {
|
||||
"(\(format(point.x)), \(format(point.y)))"
|
||||
}
|
||||
|
||||
static func describe(_ rect: CGRect) -> String {
|
||||
"(x:\(format(rect.origin.x)), y:\(format(rect.origin.y)), w:\(format(rect.size.width)), h:\(format(rect.size.height)))"
|
||||
}
|
||||
|
||||
static func describe(_ view: UIView?) -> String {
|
||||
guard let view else { return "nil" }
|
||||
let identifier = view.accessibilityIdentifier ?? "nil"
|
||||
return "\(type(of: view))(addr=\(Unmanaged.passUnretained(view).toOpaque()), id=\(identifier))"
|
||||
}
|
||||
|
||||
private static func format(_ value: CGFloat) -> String {
|
||||
String(format: "%.1f", value)
|
||||
}
|
||||
}
|
||||
|
||||
public class RDReaderView: UIView {
|
||||
|
||||
enum TapEvent {
|
||||
@@ -524,10 +571,16 @@ public class RDReaderView: UIView {
|
||||
@objc private func tapAction(tap: UITapGestureRecognizer) {
|
||||
let point = tap.location(in: tap.view)
|
||||
let hitView = hitTest(point, with: nil)
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.tapAction",
|
||||
"received point=\(RDReaderTapDebug.describe(point)) hitView=\(RDReaderTapDebug.describe(hitView)) display=\(currentDisplayType) currentPage=\(currentPage) toolVisible=\(isShowToolView) transitioning=\(isPageCurlTransitioning)"
|
||||
)
|
||||
if containsTextContentView(in: hitView) {
|
||||
RDReaderTapDebug.log("ReaderView.tapAction", "ignored because hitView is inside text content view")
|
||||
return
|
||||
}
|
||||
if shouldSuppressChromeToggle(for: hitView, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.tapAction", "ignored because chrome toggle is suppressed")
|
||||
return
|
||||
}
|
||||
handleResolvedTap(at: point, hitView: hitView, in: tap.view)
|
||||
@@ -535,13 +588,24 @@ public class RDReaderView: UIView {
|
||||
|
||||
private func shouldSuppressChromeToggle(for hitView: UIView?, point: CGPoint) -> Bool {
|
||||
if selectionTapSuppressedContentViews.allObjects.isEmpty == false {
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.suppressChromeToggle",
|
||||
"suppressed by active selectionTapSuppressedContentViews count=\(selectionTapSuppressedContentViews.allObjects.count)"
|
||||
)
|
||||
return true
|
||||
}
|
||||
var currentView = hitView
|
||||
while let view = currentView {
|
||||
if let textContentView = view as? RDEPUBTextContentView {
|
||||
let localPoint = convert(point, to: textContentView)
|
||||
return textContentView.shouldSuppressReaderTap(at: localPoint)
|
||||
let shouldSuppress = textContentView.shouldSuppressReaderTap(at: localPoint)
|
||||
if shouldSuppress {
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.suppressChromeToggle",
|
||||
"suppressed by text content view=\(RDReaderTapDebug.describe(textContentView)) localPoint=\(RDReaderTapDebug.describe(localPoint))"
|
||||
)
|
||||
}
|
||||
return shouldSuppress
|
||||
}
|
||||
currentView = view.superview
|
||||
}
|
||||
@@ -566,6 +630,10 @@ public class RDReaderView: UIView {
|
||||
} else {
|
||||
selectionTapSuppressedContentViews.remove(contentView)
|
||||
}
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.selectionTapSuppression",
|
||||
"contentView=\(RDReaderTapDebug.describe(contentView)) suppressed=\(isSuppressed) activeCount=\(selectionTapSuppressedContentViews.allObjects.count)"
|
||||
)
|
||||
}
|
||||
|
||||
func updateSelectionPagingSuppression(for contentView: UIView, isSuppressed: Bool) {
|
||||
@@ -576,18 +644,32 @@ public class RDReaderView: UIView {
|
||||
} else {
|
||||
selectionPagingSuppressedContentViews.remove(contentView)
|
||||
}
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.selectionPagingSuppression",
|
||||
"contentView=\(RDReaderTapDebug.describe(contentView)) suppressed=\(isSuppressed) activeCount=\(selectionPagingSuppressedContentViews.allObjects.count)"
|
||||
)
|
||||
updatePagingInteractionSuppression()
|
||||
}
|
||||
|
||||
func handleContentTap(at point: CGPoint, in sourceView: UIView) {
|
||||
let localPoint = sourceView.convert(point, to: self)
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.handleContentTap",
|
||||
"forwarded from sourceView=\(RDReaderTapDebug.describe(sourceView)) sourcePoint=\(RDReaderTapDebug.describe(point)) localPoint=\(RDReaderTapDebug.describe(localPoint))"
|
||||
)
|
||||
handleResolvedTap(at: localPoint, hitView: nil, in: self)
|
||||
}
|
||||
|
||||
private func handleResolvedTap(at point: CGPoint, hitView: UIView?, in tapView: UIView?) {
|
||||
if isShowToolView {
|
||||
if let top = topToolView, isHitView(hitView, inside: top, point: point) { return }
|
||||
if let bottom = bottomToolView, isHitView(hitView, inside: bottom, point: point) { return }
|
||||
if let top = topToolView, isHitView(hitView, inside: top, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.handleResolvedTap", "ignored because point hits top tool view")
|
||||
return
|
||||
}
|
||||
if let bottom = bottomToolView, isHitView(hitView, inside: bottom, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.handleResolvedTap", "ignored because point hits bottom tool view")
|
||||
return
|
||||
}
|
||||
}
|
||||
guard let viewFrame = tapView?.frame else { return }
|
||||
tapEvent = tapRegionHandler.resolveTapEvent(
|
||||
@@ -595,6 +677,10 @@ public class RDReaderView: UIView {
|
||||
viewFrame: viewFrame,
|
||||
isToolViewVisible: isShowToolView
|
||||
)
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.handleResolvedTap",
|
||||
"resolved tapEvent=\(tapEvent) point=\(RDReaderTapDebug.describe(point)) viewFrame=\(RDReaderTapDebug.describe(viewFrame))"
|
||||
)
|
||||
}
|
||||
|
||||
private func containsTextContentView(in hitView: UIView?) -> Bool {
|
||||
@@ -612,6 +698,10 @@ public class RDReaderView: UIView {
|
||||
let shouldSuppress = activePagingSuppressionContentViews().isEmpty == false
|
||||
guard shouldSuppress != isPagingInteractionSuppressed else { return }
|
||||
isPagingInteractionSuppressed = shouldSuppress
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.pagingSuppression",
|
||||
"updated shouldSuppress=\(shouldSuppress) activeContentViews=\(activePagingSuppressionContentViews().count)"
|
||||
)
|
||||
setPagingInteractionEnabled(!shouldSuppress)
|
||||
}
|
||||
|
||||
@@ -771,22 +861,37 @@ extension RDReaderView: UIGestureRecognizerDelegate {
|
||||
guard gestureRecognizer === tapGestureRecognizer else { return true }
|
||||
|
||||
if selectionTapSuppressedContentViews.allObjects.isEmpty == false {
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.gestureShouldReceive",
|
||||
"return false because selectionTapSuppressedContentViews count=\(selectionTapSuppressedContentViews.allObjects.count)"
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
let point = touch.location(in: self)
|
||||
if containsTextContentView(in: touch.view) {
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.gestureShouldReceive",
|
||||
"return false because touch.view is inside text content view point=\(RDReaderTapDebug.describe(point)) touchView=\(RDReaderTapDebug.describe(touch.view))"
|
||||
)
|
||||
return false
|
||||
}
|
||||
if let topToolView, isHitView(touch.view, inside: topToolView, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.gestureShouldReceive", "return false because touch hit topToolView")
|
||||
return false
|
||||
}
|
||||
if let bottomToolView, isHitView(touch.view, inside: bottomToolView, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.gestureShouldReceive", "return false because touch hit bottomToolView")
|
||||
return false
|
||||
}
|
||||
if let searchBarView, isHitView(touch.view, inside: searchBarView, point: point) {
|
||||
RDReaderTapDebug.log("ReaderView.gestureShouldReceive", "return false because touch hit searchBarView")
|
||||
return false
|
||||
}
|
||||
RDReaderTapDebug.log(
|
||||
"ReaderView.gestureShouldReceive",
|
||||
"return true point=\(RDReaderTapDebug.describe(point)) touchView=\(RDReaderTapDebug.describe(touch.view))"
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user