- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
80 lines
3.3 KiB
Swift
80 lines
3.3 KiB
Swift
|
|
import UIKit
|
|
|
|
extension RDEPUBReaderController {
|
|
|
|
func presentAttachmentTooltip(text: String, sourceView: UIView, sourceRect: CGRect, sourcePoint: CGPoint) {
|
|
hideAttachmentTooltipIfNeeded()
|
|
|
|
let overlay = RDEPUBAttachmentTooltipOverlayView(frame: view.bounds)
|
|
overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
overlay.onBackgroundTap = { [weak self, weak overlay] in
|
|
guard let self, let overlay else { return }
|
|
self.dismissAttachmentTooltipOverlay(overlay)
|
|
}
|
|
|
|
let tooltip = RDEPUBAttachmentTooltipView()
|
|
tooltip.alpha = 0
|
|
let horizontalPadding = max(view.safeAreaInsets.left, view.safeAreaInsets.right) + 12
|
|
tooltip.configure(text: text, maxWidth: min(view.bounds.width - horizontalPadding * 2, 320))
|
|
|
|
let anchorRect = sourceView.convert(sourceRect, to: view)
|
|
let rawAnchorPoint = sourceView.convert(sourcePoint, to: view)
|
|
let anchorPoint = CGPoint(
|
|
x: min(max(rawAnchorPoint.x, anchorRect.minX), anchorRect.maxX),
|
|
y: min(max(rawAnchorPoint.y, anchorRect.minY), anchorRect.maxY)
|
|
)
|
|
let verticalSpacing: CGFloat = 6
|
|
let tooltipSize = tooltip.frame.size
|
|
let idealX = anchorPoint.x - tooltipSize.width / 2
|
|
let minX = horizontalPadding
|
|
let maxX = max(minX, view.bounds.width - horizontalPadding - tooltipSize.width)
|
|
let originX = min(max(idealX, minX), maxX)
|
|
let topSafeY = view.safeAreaInsets.top + 12
|
|
let bottomSafeY = view.bounds.height - view.safeAreaInsets.bottom - 12
|
|
let availableSpaceAbove = anchorRect.minY - topSafeY
|
|
let availableSpaceBelow = bottomSafeY - anchorRect.maxY
|
|
let prefersAbove = availableSpaceAbove >= tooltipSize.height + verticalSpacing || availableSpaceAbove >= availableSpaceBelow
|
|
let tooltipPlacement: RDEPUBAttachmentTooltipView.ArrowPlacement = prefersAbove ? .bottom : .top
|
|
let originY: CGFloat
|
|
switch tooltipPlacement {
|
|
case .bottom:
|
|
originY = max(topSafeY, anchorRect.minY - tooltipSize.height - verticalSpacing)
|
|
case .top:
|
|
originY = min(bottomSafeY - tooltipSize.height, anchorRect.maxY + verticalSpacing)
|
|
}
|
|
let arrowTipX = min(
|
|
max(anchorPoint.x - originX, tooltip.minimumArrowX),
|
|
tooltipSize.width - tooltip.minimumArrowX
|
|
)
|
|
|
|
tooltip.setArrowTipX(arrowTipX, placement: tooltipPlacement)
|
|
tooltip.frame.origin = CGPoint(x: originX, y: originY)
|
|
overlay.addSubview(tooltip)
|
|
view.addSubview(overlay)
|
|
|
|
UIView.animate(withDuration: 0.2) {
|
|
tooltip.alpha = 1
|
|
}
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) { [weak self, weak overlay] in
|
|
guard let self, let overlay else { return }
|
|
self.dismissAttachmentTooltipOverlay(overlay)
|
|
}
|
|
}
|
|
|
|
private func hideAttachmentTooltipIfNeeded() {
|
|
view.subviews
|
|
.compactMap { $0 as? RDEPUBAttachmentTooltipOverlayView }
|
|
.forEach { $0.removeFromSuperview() }
|
|
}
|
|
|
|
private func dismissAttachmentTooltipOverlay(_ overlay: RDEPUBAttachmentTooltipOverlayView) {
|
|
UIView.animate(withDuration: 0.18, animations: {
|
|
overlay.tooltipView?.alpha = 0
|
|
}, completion: { _ in
|
|
overlay.removeFromSuperview()
|
|
})
|
|
}
|
|
}
|