feat: complete large-book pagination runtime and UI coverage
This commit is contained in:
@@ -34,7 +34,10 @@ final class RDEPUBReaderContext {
|
||||
/// 当前阅读会话,管理页面和章节状态。
|
||||
var readingSession: RDEPUBReadingSession?
|
||||
/// 原生文本排版生成的图书模型(仅文本重排模式)。
|
||||
/// 章节模式下为 nil,内容通过 ChapterRuntimeStore 访问。
|
||||
var textBook: RDEPUBTextBook?
|
||||
/// 全书轻量页码映射(章节模式)。约 100KB/1000章,不持有 NSAttributedString。
|
||||
var bookPageMap: RDEPUBBookPageMap?
|
||||
/// 当前书籍的所有书签。
|
||||
var activeBookmarks: [RDEPUBBookmark] = []
|
||||
/// 当前书籍的所有高亮标注。
|
||||
@@ -131,8 +134,9 @@ final class RDEPUBReaderContext {
|
||||
edgeInsets: configuration.reflowableContentInsets,
|
||||
numberOfColumns: configuration.numberOfColumns,
|
||||
columnGap: configuration.columnGap,
|
||||
avoidOrphans: true,
|
||||
avoidWidows: true,
|
||||
// 小说正文更看重尽量铺满页面,避免页尾出现明显留白。
|
||||
avoidOrphans: false,
|
||||
avoidWidows: false,
|
||||
avoidPageBreakInsideEnabled: true,
|
||||
hyphenation: true,
|
||||
imageMaxHeightRatio: 0.85,
|
||||
@@ -186,6 +190,66 @@ final class RDEPUBReaderContext {
|
||||
dependencies.makeTextBookBuilder(resolvedTextRenderer(), textBookCache, layoutConfig)
|
||||
}
|
||||
|
||||
func makeChapterSummaryDiskCache() -> RDEPUBChapterSummaryDiskCache {
|
||||
let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
|
||||
?? FileManager.default.temporaryDirectory
|
||||
let bookID = (currentBookIdentifier ?? "default").sha256Hex
|
||||
let directory = cachesDirectory
|
||||
.appendingPathComponent("RDEPUBChapterSummaryCache", isDirectory: true)
|
||||
.appendingPathComponent(bookID, isDirectory: true)
|
||||
return RDEPUBChapterSummaryDiskCache(cacheDirectory: directory)
|
||||
}
|
||||
|
||||
func chapterCacheKey(forSpineIndex spineIndex: Int) -> RDEPUBChapterCacheKey {
|
||||
let style = currentTextRenderStyle()
|
||||
let pageSize = currentTextPageSize()
|
||||
let layoutConfig = currentTextLayoutConfig(pageSize: pageSize)
|
||||
let renderSignature = [
|
||||
style.font.fontName,
|
||||
"\(style.font.pointSize)",
|
||||
"\(configuration.lineHeightMultiple)",
|
||||
"\(style.lineSpacing)",
|
||||
layoutConfig.cacheSignature,
|
||||
"\(RDEPUBChapterSummary.currentSchemaVersion)"
|
||||
].joined(separator: "|")
|
||||
|
||||
let contentHash: String
|
||||
if let parser,
|
||||
let publication,
|
||||
publication.spine.indices.contains(spineIndex) {
|
||||
let href = publication.spine[spineIndex].href
|
||||
contentHash = parser.htmlString(forRelativePath: href)?.sha256Hex ?? ""
|
||||
} else {
|
||||
contentHash = ""
|
||||
}
|
||||
|
||||
return RDEPUBChapterCacheKey(
|
||||
bookID: currentBookIdentifier ?? "",
|
||||
spineIndex: spineIndex,
|
||||
renderSignature: renderSignature,
|
||||
chapterContentHash: contentHash
|
||||
)
|
||||
}
|
||||
|
||||
func chapterSummary(forSpineIndex spineIndex: Int) -> RDEPUBChapterSummary? {
|
||||
runtime?.summaryDiskCache.read(for: chapterCacheKey(forSpineIndex: spineIndex))
|
||||
}
|
||||
|
||||
func normalizedSpineIndex(for location: RDEPUBLocation) -> Int? {
|
||||
guard let publication else { return nil }
|
||||
let normalizedLocation = publication.resourceResolver.normalizedLocation(
|
||||
location,
|
||||
relativeToSpineIndex: nil,
|
||||
bookIdentifier: currentBookIdentifier
|
||||
) ?? location
|
||||
guard let normalizedHref = publication.resourceResolver.normalizedHref(normalizedLocation.href) else {
|
||||
return nil
|
||||
}
|
||||
return publication.spine.firstIndex {
|
||||
publication.resourceResolver.normalizedHref($0.href) == normalizedHref
|
||||
}
|
||||
}
|
||||
|
||||
/// 工厂方法:创建纯文本图书构建器。
|
||||
func makePlainTextBookBuilder(layoutConfig: RDEPUBTextLayoutConfig) -> RDPlainTextBookBuilder {
|
||||
dependencies.makePlainTextBookBuilder(resolvedTextRenderer(), layoutConfig)
|
||||
|
||||
Reference in New Issue
Block a user