feat: EPUB阅读器搜索、注释、CFI模块及大书远距跳转优化

- 实现EPUB阅读器搜索功能及选中注释功能
- 优化CFI模块,修复代码审查发现的11个问题
- 实现大书远距目录跳转与后台补全优化方案
- 优化设置面板与章节运行时联动
- 重构及大量改进优化
This commit is contained in:
shenlei
2026-06-22 20:26:34 +08:00
parent f50495ad91
commit c65c190b71
178 changed files with 11380 additions and 6728 deletions
@@ -1,26 +1,18 @@
import UIKit
// MARK: -
/// EPUB
///
public enum RDEPUBTextRenderingEngine: Equatable {
/// DTCoreText HTML/CSS NSAttributedString
case dtCoreText
}
// MARK: -
///
/// 使 bundle
public enum RDEPUBReaderFontChoice: String, Codable, CaseIterable, Equatable {
/// 线
case system
/// 线
case serif
///
case rounded
///
case monospaced
public var displayName: String {
@@ -54,108 +46,58 @@ public enum RDEPUBReaderFontChoice: String, Codable, CaseIterable, Equatable {
}
}
// MARK: -
/// EPUB
/// EPUBUI
/// RDEPUBReaderController
public struct RDEPUBReaderConfiguration: Equatable {
// MARK:
/// pt 15
public var fontSize: CGFloat
/// 1.6 1.6
public var lineHeightMultiple: CGFloat
///
public var fontChoice: RDEPUBReaderFontChoice
///
public var numberOfColumns: Int
/// 20pt
public var columnGap: CGFloat
/// .pageCurl仿 .scroll
public var displayType: RDReaderView.DisplayType
///
public var landscapeDualPageEnabled: Bool
// MARK: UI
///
public var showsTableOfContents: Bool
///
public var allowsHighlights: Bool
///
public var showsSettingsPanel: Bool
// MARK:
/// reflowable 40pt 16pt
public var reflowableContentInsets: UIEdgeInsets
/// fixed layout
public var fixedContentInset: UIEdgeInsets
// MARK:
/// // .light
public var theme: RDEPUBReaderTheme
///
public var darkImageAdjustmentEnabled: Bool
/// 0 0.12 ~ 0.2
public var darkImageBlendRatio: CGFloat
///
public var fixedLayoutFit: RDEPUBFixedLayoutFit
/// //
public var fixedLayoutSpreadMode: RDEPUBFixedLayoutSpreadMode
/// 使 DTCoreText
public var textRenderingEngine: RDEPUBTextRenderingEngine
/// 3 3...15
public var onDemandChapterWindowSize: Int
/// CPU
/// profiling renderTotalMs wallClockMs
/// writeTotalMs I/O cpuCount * 1.25~1.5 I/O
public var metadataParsingConcurrency: Int
// MARK: JumpSession
/// JumpSession
public var jumpSessionPolicy: RDEPUBJumpSessionPolicy
// MARK:
/// URL scheme https
public var allowedExternalURLSchemes: Set<String>
/// true
public var requiresExternalLinkConfirmation: Bool
/// WebView inspectable false
public var allowsInspectableWebViews: Bool
/// WebView false
public var enablesVerboseWebViewLogging: Bool
// MARK:
///
/// - Parameters:
/// - fontSize: 15pt
/// - lineHeightMultiple: 1.6
/// - fontChoice:
/// - displayType: .pageCurl
/// - landscapeDualPageEnabled: true
/// - showsTableOfContents: true
/// - allowsHighlights: true
/// - showsSettingsPanel: true
/// - reflowableContentInsets:
/// - fixedContentInset:
/// - theme: .light
/// - darkImageAdjustmentEnabled:
/// - darkImageBlendRatio:
/// - fixedLayoutFit:
/// - fixedLayoutSpreadMode:
/// - textRenderingEngine:
/// - onDemandChapterWindowSize: 3...15
/// - metadataParsingConcurrency: CPU
/// - allowedExternalURLSchemes: URL scheme https
/// - requiresExternalLinkConfirmation: true
/// - allowsInspectableWebViews: inspectable false
/// - enablesVerboseWebViewLogging: WebView false
public init(
fontSize: CGFloat = 15,
lineHeightMultiple: CGFloat = 1.6,
@@ -210,11 +152,11 @@ public struct RDEPUBReaderConfiguration: Equatable {
self.enablesVerboseWebViewLogging = enablesVerboseWebViewLogging
}
/// 使
public static let `default` = RDEPUBReaderConfiguration()
}
extension RDEPUBReaderConfiguration {
static func normalizedChapterWindowSize(_ size: Int) -> Int {
let clamped = max(3, min(15, size))
return clamped % 2 == 0 ? clamped + 1 : clamped
@@ -225,11 +167,8 @@ extension RDEPUBReaderConfiguration {
}
}
// MARK: -
extension RDEPUBReaderConfiguration {
/// RDEPUBPreferences
/// - Returns: Core 使
func makePreferences() -> RDEPUBPreferences {
RDEPUBPreferences(
fontSize: fontSize,
@@ -1,20 +1,15 @@
import UIKit
// MARK: -
///
/// RDReaderView.DisplayType
public enum RDEPUBReaderDisplayMode: String, Codable, Equatable {
/// 仿
case pageCurl
///
case horizontalScroll
///
case verticalScroll
///
case horizontalCoverScroll
/// DisplayType UI DisplayMode
init(displayType: RDReaderView.DisplayType) {
switch displayType {
case .pageCurl:
@@ -26,8 +21,6 @@ public enum RDEPUBReaderDisplayMode: String, Codable, Equatable {
}
}
/// RDReaderView DisplayType
/// horizontalCoverScroll horizontalScroll
var displayType: RDReaderView.DisplayType {
switch self {
case .pageCurl:
@@ -40,25 +33,20 @@ public enum RDEPUBReaderDisplayMode: String, Codable, Equatable {
}
}
// MARK: -
///
/// RDEPUBReaderTheme
public enum RDEPUBReaderThemePreset: String, Codable, CaseIterable, Equatable {
///
case light
///
case yellow
/// 绿
case green
///
case pink
///
case blue
/// /
case dark
///
public var theme: RDEPUBReaderTheme {
switch self {
case .light:
@@ -76,8 +64,6 @@ public enum RDEPUBReaderThemePreset: String, Codable, CaseIterable, Equatable {
}
}
///
/// nil
public init?(theme: RDEPUBReaderTheme) {
switch theme {
case .light:
@@ -98,30 +84,22 @@ public enum RDEPUBReaderThemePreset: String, Codable, CaseIterable, Equatable {
}
}
// MARK: -
///
///
///
public struct RDEPUBReaderSettings: Codable, Equatable {
// MARK:
/// 0.0 ~ 1.0nil 使
public var brightness: CGFloat?
/// ptnil 使
public var fontSize: CGFloat?
/// nil 使
public var fontChoice: RDEPUBReaderFontChoice?
/// nil 使
public var lineHeightMultiple: CGFloat?
/// nil 使
public var numberOfColumns: Int?
/// nil 使
public var displayMode: RDEPUBReaderDisplayMode?
/// nil 使
public var themePreset: RDEPUBReaderThemePreset?
/// nil
public init(
brightness: CGFloat? = nil,
fontSize: CGFloat? = nil,
@@ -140,10 +118,6 @@ public struct RDEPUBReaderSettings: Codable, Equatable {
self.themePreset = themePreset
}
///
/// nil
/// - Parameter configuration: RDEPUBReaderConfiguration.default
/// - Returns:
public func applying(to configuration: RDEPUBReaderConfiguration) -> RDEPUBReaderConfiguration {
var resolvedConfiguration = configuration
@@ -169,12 +143,6 @@ public struct RDEPUBReaderSettings: Codable, Equatable {
return resolvedConfiguration
}
///
/// 0.0 ~ 1.0
/// - Parameters:
/// - configuration:
/// - brightness:
/// - Returns:
public static func capture(
configuration: RDEPUBReaderConfiguration,
brightness: CGFloat
@@ -1,33 +1,23 @@
import UIKit
// MARK: -
/// EPUB
///
/// iOS 13+ SF Symbols 退
final class RDEPUBReaderSettingsViewController: UIViewController {
// MARK:
/// 0.0 ~ 1.0
var onBrightnessChange: ((CGFloat) -> Void)?
/// pt
var onFontSizeChange: ((CGFloat) -> Void)?
///
var onFontChoiceChange: ((RDEPUBReaderFontChoice) -> Void)?
///
var onLineHeightChange: ((CGFloat) -> Void)?
///
var onColumnCountChange: ((Int) -> Void)?
///
var onDisplayTypeChange: ((RDReaderView.DisplayType) -> Void)?
///
var onThemeChange: ((RDEPUBReaderTheme) -> Void)?
///
var onDismiss: (() -> Void)?
// MARK:
///
private enum ThemePreset: Int, CaseIterable {
case light
case yellow
@@ -60,20 +50,30 @@ final class RDEPUBReaderSettingsViewController: UIViewController {
}
private let scrollView = UIScrollView()
private let contentStack: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 20
return stackView
}()
private let brightnessSlider = UISlider()
private let fontValueLabel = UILabel()
private let decreaseFontButton = UIButton(type: .system)
private let increaseFontButton = UIButton(type: .system)
private let fontChoiceControl = UISegmentedControl(items: RDEPUBReaderFontChoice.allCases.map(\.displayName))
private let lineHeightControl = UISegmentedControl(items: ["紧凑", "标准", "宽松"])
private let columnCountControl = UISegmentedControl(items: ["单栏", "双栏"])
private let displayTypeControl = UISegmentedControl(items: ["仿真", "横滑", "竖滑"])
private let themeStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
@@ -81,11 +81,11 @@ final class RDEPUBReaderSettingsViewController: UIViewController {
stackView.spacing = 12
return stackView
}()
private var themeButtons: [UIButton] = []
/// 1.3 1.6 1.9
private let lineHeightValues: [CGFloat] = [1.3, 1.6, 1.9]
///
private var currentConfiguration: RDEPUBReaderConfiguration
init(configuration: RDEPUBReaderConfiguration, brightness: CGFloat) {
@@ -1,37 +1,19 @@
import UIKit
// MARK: -
/// EPUB
///
/// 绿
public struct RDEPUBReaderTheme: Equatable {
// MARK:
///
public var contentBackgroundColor: UIColor
///
public var contentTextColor: UIColor
// MARK:
///
public var toolBackgroundColor: UIColor
/// /
public var toolControlTextColor: UIColor
///
public var toolControlBorderUnselectColor: UIColor
/// 线
public var toolLineColor: UIColor
///
/// - Parameters:
/// - contentBackgroundColor:
/// - contentTextColor:
/// - toolBackgroundColor:
/// - toolControlTextColor:
/// - toolControlBorderUnselectColor:
/// - toolLineColor: 线
public init(
contentBackgroundColor: UIColor,
contentTextColor: UIColor,
@@ -48,9 +30,6 @@ public struct RDEPUBReaderTheme: Equatable {
self.toolLineColor = toolLineColor
}
// MARK:
///
public static let light = RDEPUBReaderTheme(
contentBackgroundColor: .white,
contentTextColor: .black,
@@ -60,7 +39,6 @@ public struct RDEPUBReaderTheme: Equatable {
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
)
///
public static let dark = RDEPUBReaderTheme(
contentBackgroundColor: .black,
contentTextColor: .white,
@@ -70,7 +48,6 @@ public struct RDEPUBReaderTheme: Equatable {
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
)
///
public static let yellow = RDEPUBReaderTheme(
contentBackgroundColor: UIColor(red: 0.89, green: 0.87, blue: 0.79, alpha: 1),
contentTextColor: .black,
@@ -80,7 +57,6 @@ public struct RDEPUBReaderTheme: Equatable {
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
)
/// 绿绿
public static let green = RDEPUBReaderTheme(
contentBackgroundColor: UIColor(red: 0.87, green: 0.91, blue: 0.82, alpha: 1),
contentTextColor: .black,
@@ -90,7 +66,6 @@ public struct RDEPUBReaderTheme: Equatable {
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
)
///
public static let pink = RDEPUBReaderTheme(
contentBackgroundColor: UIColor(red: 1, green: 0.89, blue: 0.91, alpha: 1),
contentTextColor: .black,
@@ -100,7 +75,6 @@ public struct RDEPUBReaderTheme: Equatable {
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
)
///
public static let blue = RDEPUBReaderTheme(
contentBackgroundColor: UIColor(red: 0.8, green: 0.84, blue: 0.89, alpha: 1),
contentTextColor: .black,
@@ -111,15 +85,12 @@ public struct RDEPUBReaderTheme: Equatable {
)
}
// MARK: - CSS
extension RDEPUBReaderTheme {
/// CSS EPUB HTML
var themeBackgroundColorCSS: String {
contentBackgroundColor.ss_cssString
}
/// CSS EPUB HTML
var themeTextColorCSS: String {
contentTextColor.ss_cssString
}