fix(reader): stabilize pagination display and page curl reuse
This commit is contained in:
@@ -114,6 +114,7 @@ final class RDEPUBTextContentView: UIView {
|
||||
|
||||
private var coreTextDisplayContent: NSAttributedString?
|
||||
private var coreTextDisplayRange: NSRange?
|
||||
private var coreTextDisplayOffsetBase: Int = 0
|
||||
#endif
|
||||
|
||||
private let interactionController = RDEPUBPageInteractionController()
|
||||
@@ -256,7 +257,7 @@ final class RDEPUBTextContentView: UIView {
|
||||
coverImageView.isHidden = true
|
||||
coverImageView.image = nil
|
||||
|
||||
let selectionContent = NSMutableAttributedString(attributedString: page.content)
|
||||
let selectionContent = normalizedPageContent(from: page)
|
||||
let selectionRange = NSRange(location: 0, length: selectionContent.length)
|
||||
selectionContent.addAttribute(
|
||||
.foregroundColor,
|
||||
@@ -265,7 +266,10 @@ final class RDEPUBTextContentView: UIView {
|
||||
)
|
||||
|
||||
#if canImport(DTCoreText)
|
||||
let displayContent = NSMutableAttributedString(attributedString: page.content)
|
||||
let usesChapterContextDisplay = shouldUseChapterContextDisplay(for: page)
|
||||
let displayContent = usesChapterContextDisplay
|
||||
? NSMutableAttributedString(attributedString: page.chapterContent)
|
||||
: normalizedPageContent(from: page)
|
||||
let fullRange = NSRange(location: 0, length: displayContent.length)
|
||||
displayContent.addAttribute(
|
||||
.foregroundColor,
|
||||
@@ -275,7 +279,8 @@ final class RDEPUBTextContentView: UIView {
|
||||
coreTextContentView.isHidden = false
|
||||
coreTextContentView.backgroundColor = .clear
|
||||
coreTextDisplayContent = displayContent
|
||||
coreTextDisplayRange = NSRange(location: 0, length: displayContent.length)
|
||||
coreTextDisplayRange = usesChapterContextDisplay ? page.contentRange : NSRange(location: 0, length: displayContent.length)
|
||||
coreTextDisplayOffsetBase = usesChapterContextDisplay ? 0 : page.pageStartOffset
|
||||
textView.isHidden = true
|
||||
textView.isUserInteractionEnabled = false
|
||||
textView.attributedText = nil
|
||||
@@ -646,6 +651,47 @@ final class RDEPUBTextContentView: UIView {
|
||||
return proxy
|
||||
}
|
||||
|
||||
private func normalizedPageContent(from page: RDEPUBTextPage) -> NSMutableAttributedString {
|
||||
let content = NSMutableAttributedString(attributedString: page.content)
|
||||
guard shouldNormalizeContinuationParagraph(for: page) else {
|
||||
return content
|
||||
}
|
||||
|
||||
let text = content.string as NSString
|
||||
let firstParagraphRange = text.paragraphRange(for: NSRange(location: 0, length: 0))
|
||||
guard firstParagraphRange.length > 0 else {
|
||||
return content
|
||||
}
|
||||
|
||||
content.enumerateAttribute(.paragraphStyle, in: firstParagraphRange) { value, range, _ in
|
||||
guard let style = value as? NSParagraphStyle else { return }
|
||||
let mutableStyle = (style.mutableCopy() as? NSMutableParagraphStyle) ?? NSMutableParagraphStyle()
|
||||
mutableStyle.firstLineHeadIndent = mutableStyle.headIndent
|
||||
mutableStyle.paragraphSpacingBefore = 0
|
||||
content.addAttribute(.paragraphStyle, value: mutableStyle.copy() as Any, range: range)
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
private func shouldNormalizeContinuationParagraph(for page: RDEPUBTextPage) -> Bool {
|
||||
let pageStart = page.pageStartOffset
|
||||
guard pageStart > 0, pageStart < page.chapterContent.length else {
|
||||
return false
|
||||
}
|
||||
|
||||
let chapterText = page.chapterContent.string as NSString
|
||||
guard let previousScalar = UnicodeScalar(chapterText.character(at: pageStart - 1)) else {
|
||||
return false
|
||||
}
|
||||
|
||||
return !CharacterSet.newlines.contains(previousScalar)
|
||||
}
|
||||
|
||||
private func shouldUseChapterContextDisplay(for page: RDEPUBTextPage) -> Bool {
|
||||
page.metadata.attachmentRanges.isEmpty
|
||||
}
|
||||
|
||||
#if canImport(DTCoreText)
|
||||
private func updateCoreTextLayoutFrameIfNeeded() {
|
||||
guard !coreTextContentView.isHidden,
|
||||
@@ -666,7 +712,11 @@ final class RDEPUBTextContentView: UIView {
|
||||
layouter.shouldCacheLayoutFrames = false
|
||||
let layoutFrame = layouter.layoutFrame(with: coreTextContentView.bounds, range: displayRange)
|
||||
coreTextContentView.layoutFrame = layoutFrame
|
||||
interactionController.configure(layoutFrame: layoutFrame, page: page)
|
||||
interactionController.configure(
|
||||
layoutFrame: layoutFrame,
|
||||
page: page,
|
||||
contentOffsetBase: coreTextDisplayOffsetBase
|
||||
)
|
||||
overlayView.updateSnapshot(interactionController.snapshot)
|
||||
backgroundOverlayView.updateSnapshot(interactionController.snapshot)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user