Fix reader interaction and web resource handling
This commit is contained in:
@@ -219,9 +219,16 @@ final class RDEPUBTextContentInteractionCoordinator: NSObject {
|
||||
private func updateSelectionInteractionState(_ state: SelectionInteractionState) {
|
||||
let previousTapSuppressed = interactionState != .idle
|
||||
let previousPagingSuppressed = shouldSuppressPagingInteraction(for: interactionState)
|
||||
let previousState = interactionState
|
||||
interactionState = state
|
||||
let currentTapSuppressed = interactionState != .idle
|
||||
let currentPagingSuppressed = shouldSuppressPagingInteraction(for: interactionState)
|
||||
if previousState != state {
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentInteraction.state",
|
||||
"transition \(previousState) -> \(state) tapSuppressed=\(currentTapSuppressed) pagingSuppressed=\(currentPagingSuppressed)"
|
||||
)
|
||||
}
|
||||
if previousTapSuppressed != currentTapSuppressed {
|
||||
dependencies.selectionTapSuppressionDidChange(currentTapSuppressed)
|
||||
}
|
||||
|
||||
@@ -727,6 +727,10 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
|| interactionCoordinator.interactionState != .idle
|
||||
guard isUserInteractionEnabled != shouldEnableInteraction else { return }
|
||||
isUserInteractionEnabled = shouldEnableInteraction
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentView.interactionAvailability",
|
||||
"updated isUserInteractionEnabled=\(shouldEnableInteraction) currentPage=\(currentPage?.absolutePageIndex ?? -1) loading=\(loadingSpinner.isAnimating) selecting=\(selectionController.isSelecting) hasSelection=\(selectionController.hasActiveSelection) state=\(interactionCoordinator.interactionState)"
|
||||
)
|
||||
}
|
||||
|
||||
private func updateStaticGestureAvailability() {
|
||||
@@ -737,24 +741,36 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
guard longPressChanged || tapChanged else { return }
|
||||
longPressGestureRecognizer.isEnabled = shouldEnableLongPress
|
||||
tapGestureRecognizer.isEnabled = shouldEnableTap
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentView.gestureAvailability",
|
||||
"updated longPressEnabled=\(shouldEnableLongPress) tapEnabled=\(shouldEnableTap) hasInteractiveTextContent=\(hasInteractiveTextContent) loading=\(loadingSpinner.isAnimating) currentPage=\(currentPage?.absolutePageIndex ?? -1)"
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func handleTap(_ gesture: UITapGestureRecognizer) {
|
||||
let point = gesture.location(in: overlayView)
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentView.handleTap",
|
||||
"received point=\(RDReaderTapDebug.describe(point)) currentPage=\(currentPage?.absolutePageIndex ?? -1) selectionState=\(interactionCoordinator.interactionState) hasSelection=\(currentSelection != nil) loading=\(loadingSpinner.isAnimating)"
|
||||
)
|
||||
if let renderView = coreTextRenderView {
|
||||
let renderPoint = gesture.location(in: renderView)
|
||||
if renderView.selectionHandle(at: renderPoint) != nil {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "ignored because tap hit selection handle")
|
||||
return
|
||||
}
|
||||
if currentSelection != nil {
|
||||
if renderView.selectionContains(renderPoint) {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "selection exists and tap stayed inside selection; showing selection menu")
|
||||
showSelectionMenuIfNeeded()
|
||||
return
|
||||
}
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "selection exists and tap moved outside selection; clearing selection")
|
||||
clearSelection()
|
||||
return
|
||||
}
|
||||
} else if currentSelection != nil {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "selection exists without renderView; clearing selection")
|
||||
clearSelection()
|
||||
return
|
||||
}
|
||||
@@ -766,6 +782,7 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
// Footnote attachments carry their note text in alt/accessibility metadata.
|
||||
// Prefer that semantic text over image preview even if attachment kind metadata is incomplete.
|
||||
if let footnoteText = attachmentText(at: point), kind == .footnote || !footnoteText.isEmpty {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "resolved footnote attachment tap")
|
||||
delegate?.textContentView(
|
||||
self,
|
||||
didActivateAttachmentText: footnoteText,
|
||||
@@ -777,12 +794,14 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
// Regular image attachments: present image viewer
|
||||
if let image = imageFromPage(attachment: attachment, page: page) {
|
||||
let altText = attachmentText(at: point)
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "resolved image attachment tap altTextPresent=\(altText?.isEmpty == false)")
|
||||
delegate?.textContentView(self, didActivateImage: image, sourceRect: sourceRect, altText: altText)
|
||||
return
|
||||
}
|
||||
}
|
||||
if let attachmentText = attachmentText(at: point),
|
||||
let sourceRect = attachmentSourceRect(at: point, fallbackPoint: point) {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "resolved fallback attachment text tap")
|
||||
delegate?.textContentView(
|
||||
self,
|
||||
didActivateAttachmentText: attachmentText,
|
||||
@@ -793,9 +812,11 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
}
|
||||
guard let highlight = highlight(at: point),
|
||||
let sourceRect = highlightSourceRect(for: highlight, fallbackPoint: point) else {
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "forwarding plain reader tap to delegate")
|
||||
delegate?.textContentView(self, didRequestReaderTapAt: convert(point, from: overlayView))
|
||||
return
|
||||
}
|
||||
RDReaderTapDebug.log("TextContentView.handleTap", "resolved highlight tap highlightId=\(highlight.id)")
|
||||
delegate?.textContentView(self, didRequestHighlightActions: highlight, sourceRect: sourceRect)
|
||||
}
|
||||
|
||||
@@ -935,26 +956,36 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
func shouldSuppressReaderTap(at point: CGPoint) -> Bool {
|
||||
#if canImport(DTCoreText)
|
||||
if interactionCoordinator.interactionState == .selectionPending {
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return true because interactionState is selectionPending")
|
||||
return true
|
||||
}
|
||||
|
||||
guard let renderView = coreTextRenderView else {
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return false because renderView is nil")
|
||||
return false
|
||||
}
|
||||
let renderPoint = convert(point, to: renderView)
|
||||
if renderView.selectionHandle(at: renderPoint) != nil {
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return true because tap hit selection handle")
|
||||
return true
|
||||
}
|
||||
if selectionController.hasActiveSelection, renderView.selectionContains(renderPoint) {
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return true because tap is inside active selection")
|
||||
return true
|
||||
}
|
||||
switch interactionCoordinator.interactionState {
|
||||
case .idle:
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return false because interactionState is idle")
|
||||
return false
|
||||
case .selectionPending, .selecting, .selectionActive, .adjustingHandle:
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentView.shouldSuppressReaderTap",
|
||||
"return true because interactionState=\(interactionCoordinator.interactionState)"
|
||||
)
|
||||
return true
|
||||
}
|
||||
#else
|
||||
RDReaderTapDebug.log("TextContentView.shouldSuppressReaderTap", "return false because DTCoreText is unavailable")
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
@@ -1003,16 +1034,23 @@ final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate, RDReader
|
||||
) -> Bool {
|
||||
if gestureRecognizer === tapGestureRecognizer {
|
||||
guard let renderView = coreTextRenderView else {
|
||||
RDReaderTapDebug.log("TextContentView.gestureShouldReceive", "return true because renderView is nil")
|
||||
return true
|
||||
}
|
||||
|
||||
let point = touch.location(in: renderView)
|
||||
if renderView.selectionHandle(at: point) != nil {
|
||||
RDReaderTapDebug.log("TextContentView.gestureShouldReceive", "return false because tap hit selection handle")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return interactionCoordinator.gestureRecognizer(gestureRecognizer, shouldReceive: touch)
|
||||
let result = interactionCoordinator.gestureRecognizer(gestureRecognizer, shouldReceive: touch)
|
||||
RDReaderTapDebug.log(
|
||||
"TextContentView.gestureShouldReceive",
|
||||
"gesture=\(type(of: gestureRecognizer)) touchView=\(RDReaderTapDebug.describe(touch.view)) result=\(result)"
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
func gestureRecognizer(
|
||||
|
||||
Reference in New Issue
Block a user