- 给全部 78 个 Swift 源文件添加详细的中文注释(文件级、类级、方法级) - 删除 LegacyRDReaderController/ 死代码目录(16 文件 4592 行) - 根目录翻页容器文件移入 ReaderView/ 目录 - Resources/ 移入 EPUBCore/Resources/(与使用者归属一致) - RDEPUBTextIndexTable.swift 移入 EPUBTextRendering/(消除反向依赖) - RDURLReaderController.swift 移入 EPUBUI/(入口控制器归入 UI 层) - 更新 podspec 资源路径
131 lines
4.3 KiB
Swift
131 lines
4.3 KiB
Swift
// RDEPUBSearchModels.swift
|
||
// EPUB 搜索相关数据模型
|
||
// 定义搜索匹配项(RDEPUBSearchMatch)、搜索结果(RDEPUBSearchResult)、
|
||
// 搜索状态(RDEPUBSearchState)和搜索展示(RDEPUBSearchPresentation)等数据结构。
|
||
|
||
import Foundation
|
||
|
||
/// 搜索匹配项,包含匹配位置、进度、预览文本和范围信息
|
||
public struct RDEPUBSearchMatch: Codable, Equatable {
|
||
/// 匹配所在资源的规范化 href
|
||
public var href: String
|
||
/// 匹配位置在文本中的进度比例(0.0 ~ 1.0)
|
||
public var progression: Double
|
||
/// 匹配位置前后的预览文本
|
||
public var previewText: String
|
||
/// 在当前资源内的本地匹配索引
|
||
public var localMatchIndex: Int
|
||
/// 匹配范围的起始位置(字符偏移量)
|
||
public var rangeLocation: Int?
|
||
/// 匹配范围的长度
|
||
public var rangeLength: Int
|
||
/// 文本范围锚点(用于精确定位)
|
||
public var rangeAnchor: RDEPUBTextRangeAnchor?
|
||
|
||
public init(
|
||
href: String,
|
||
progression: Double,
|
||
previewText: String,
|
||
localMatchIndex: Int,
|
||
rangeLocation: Int? = nil,
|
||
rangeLength: Int,
|
||
rangeAnchor: RDEPUBTextRangeAnchor? = nil
|
||
) {
|
||
self.href = href
|
||
self.progression = progression
|
||
self.previewText = previewText
|
||
self.localMatchIndex = localMatchIndex
|
||
self.rangeLocation = rangeLocation
|
||
self.rangeLength = rangeLength
|
||
self.rangeAnchor = rangeAnchor
|
||
}
|
||
}
|
||
|
||
/// 搜索结果摘要,包含关键词、总匹配数和当前匹配项
|
||
public struct RDEPUBSearchResult: Codable, Equatable {
|
||
/// 搜索关键词
|
||
public var keyword: String
|
||
/// 总匹配数量
|
||
public var totalMatchCount: Int
|
||
/// 当前匹配项的索引(从 1 开始)
|
||
public var currentMatchIndex: Int?
|
||
/// 当前高亮的匹配项
|
||
public var currentMatch: RDEPUBSearchMatch?
|
||
|
||
public init(
|
||
keyword: String,
|
||
totalMatchCount: Int,
|
||
currentMatchIndex: Int?,
|
||
currentMatch: RDEPUBSearchMatch?
|
||
) {
|
||
self.keyword = keyword
|
||
self.totalMatchCount = totalMatchCount
|
||
self.currentMatchIndex = currentMatchIndex
|
||
self.currentMatch = currentMatch
|
||
}
|
||
}
|
||
|
||
/// 搜索状态,管理关键词、匹配列表和当前索引
|
||
public struct RDEPUBSearchState: Codable, Equatable {
|
||
/// 搜索关键词
|
||
public var keyword: String
|
||
/// 所有匹配项列表
|
||
public var matches: [RDEPUBSearchMatch]
|
||
/// 当前匹配项索引(从 0 开始)
|
||
public var currentMatchIndex: Int?
|
||
|
||
public init(keyword: String, matches: [RDEPUBSearchMatch], currentMatchIndex: Int? = nil) {
|
||
self.keyword = keyword
|
||
self.matches = matches
|
||
self.currentMatchIndex = currentMatchIndex
|
||
}
|
||
|
||
/// 获取当前匹配项
|
||
public var currentMatch: RDEPUBSearchMatch? {
|
||
guard let currentMatchIndex,
|
||
matches.indices.contains(currentMatchIndex) else {
|
||
return nil
|
||
}
|
||
return matches[currentMatchIndex]
|
||
}
|
||
|
||
/// 转换为搜索结果摘要
|
||
public var result: RDEPUBSearchResult {
|
||
RDEPUBSearchResult(
|
||
keyword: keyword,
|
||
totalMatchCount: matches.count,
|
||
currentMatchIndex: currentMatchIndex.map { $0 + 1 },
|
||
currentMatch: currentMatch
|
||
)
|
||
}
|
||
}
|
||
|
||
/// 搜索展示的单个资源信息
|
||
public struct RDEPUBSearchPresentationResource: Codable, Equatable {
|
||
/// 资源的规范化 href
|
||
public var href: String
|
||
/// 该资源内的匹配数量
|
||
public var matchCount: Int
|
||
/// 当前活跃的本地匹配索引
|
||
public var activeLocalMatchIndex: Int?
|
||
|
||
public init(href: String, matchCount: Int, activeLocalMatchIndex: Int? = nil) {
|
||
self.href = href
|
||
self.matchCount = matchCount
|
||
self.activeLocalMatchIndex = activeLocalMatchIndex
|
||
}
|
||
}
|
||
|
||
/// 搜索展示信息,传递给 JS 桥接脚本用于渲染搜索高亮
|
||
public struct RDEPUBSearchPresentation: Codable, Equatable {
|
||
/// 搜索关键词
|
||
public var keyword: String
|
||
/// 各资源的搜索展示信息列表
|
||
public var resources: [RDEPUBSearchPresentationResource]
|
||
|
||
public init(keyword: String, resources: [RDEPUBSearchPresentationResource]) {
|
||
self.keyword = keyword
|
||
self.resources = resources
|
||
}
|
||
}
|