Files
ReadViewSDK/Sources/RDEpubReaderView/EPUBUI/Settings/RDEPUBReaderConfiguration.swift
T
shenlei d7fcda345d refactor: rename RDReaderView -> RDEpubReaderView, update pod config and docs
- 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
2026-07-10 19:44:53 +09:00

216 lines
7.9 KiB
Swift

import UIKit
public enum RDEPUBTextRenderingEngine: Equatable {
case dtCoreText
}
public enum RDEPUBReaderFontChoice: String, Codable, CaseIterable, Equatable {
case system
case serif
case rounded
case monospaced
public var displayName: String {
switch self {
case .system:
return "系统"
case .serif:
return "宋体"
case .rounded:
return "圆体"
case .monospaced:
return "等宽"
}
}
public func font(ofSize size: CGFloat) -> UIFont {
switch self {
case .system:
return UIFont.systemFont(ofSize: size)
case .serif:
let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
.withDesign(.serif) ?? UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
return UIFont(descriptor: descriptor, size: size)
case .rounded:
let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
.withDesign(.rounded) ?? UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
return UIFont(descriptor: descriptor, size: size)
case .monospaced:
return UIFont.monospacedSystemFont(ofSize: size, weight: .regular)
}
}
}
/// 试读策略:开启后,阅读器在最后一个可读页之后追加一页“试读墙”(UI 由宿主经 delegate 提供)。
public struct RDEPUBReaderTrialPolicy: Equatable {
/// 可读章节数(可读 spine 为 0..<readableChapterCount)。
/// nil = 全书可读,试读墙追加在全书末尾(对应 readoor 的独立试读 epub:整本都是试读章节)。
/// 指定数值时超出范围的章节页不再展示(对应“整本 epub + 按章限制”形态,仅 bookPageMap 路径生效)。
public var readableChapterCount: Int?
public init(readableChapterCount: Int? = nil) {
self.readableChapterCount = readableChapterCount
}
}
public struct RDEPUBReaderConfiguration: Equatable {
public var fontSize: CGFloat
public var lineHeightMultiple: CGFloat
public var fontChoice: RDEPUBReaderFontChoice
public var numberOfColumns: Int
public var columnGap: CGFloat
public var displayType: RDEpubReaderView.DisplayType
public var landscapeDualPageEnabled: Bool
public var showsTableOfContents: Bool
public var allowsHighlights: Bool
public var showsSettingsPanel: Bool
public var reflowableContentInsets: UIEdgeInsets
public var fixedContentInset: UIEdgeInsets
public var theme: RDEPUBReaderTheme
public var darkImageAdjustmentEnabled: Bool
public var darkImageBlendRatio: CGFloat
public var fixedLayoutFit: RDEPUBFixedLayoutFit
public var fixedLayoutSpreadMode: RDEPUBFixedLayoutSpreadMode
public var textRenderingEngine: RDEPUBTextRenderingEngine
public var onDemandChapterWindowSize: Int
public var metadataParsingConcurrency: Int
public var jumpSessionPolicy: RDEPUBJumpSessionPolicy
public var allowedExternalURLSchemes: Set<String>
public var requiresExternalLinkConfirmation: Bool
public var allowsInspectableWebViews: Bool
public var enablesVerboseWebViewLogging: Bool
/// 试读策略;nil = 非试读(全书可读、无试读墙)。
public var trialPolicy: RDEPUBReaderTrialPolicy?
public init(
fontSize: CGFloat = 15,
lineHeightMultiple: CGFloat = 1.6,
fontChoice: RDEPUBReaderFontChoice = .system,
numberOfColumns: Int = 1,
columnGap: CGFloat = 20,
displayType: RDEpubReaderView.DisplayType = .pageCurl,
landscapeDualPageEnabled: Bool = true,
showsTableOfContents: Bool = true,
allowsHighlights: Bool = true,
showsSettingsPanel: Bool = true,
reflowableContentInsets: UIEdgeInsets = RDEPUBSafeArea.defaultReflowableContentInsets(),
fixedContentInset: UIEdgeInsets = .zero,
theme: RDEPUBReaderTheme = .light,
darkImageAdjustmentEnabled: Bool = true,
darkImageBlendRatio: CGFloat = 0.15,
fixedLayoutFit: RDEPUBFixedLayoutFit = .page,
fixedLayoutSpreadMode: RDEPUBFixedLayoutSpreadMode = .automatic,
textRenderingEngine: RDEPUBTextRenderingEngine = .dtCoreText,
onDemandChapterWindowSize: Int = 3,
metadataParsingConcurrency: Int = ProcessInfo.processInfo.activeProcessorCount,
jumpSessionPolicy: RDEPUBJumpSessionPolicy = .default,
allowedExternalURLSchemes: Set<String> = ["https"],
requiresExternalLinkConfirmation: Bool = true,
allowsInspectableWebViews: Bool = false,
enablesVerboseWebViewLogging: Bool = false,
trialPolicy: RDEPUBReaderTrialPolicy? = nil
) {
self.fontSize = fontSize
self.lineHeightMultiple = lineHeightMultiple
self.fontChoice = fontChoice
self.numberOfColumns = max(1, numberOfColumns)
self.columnGap = max(0, columnGap)
self.displayType = displayType
self.landscapeDualPageEnabled = landscapeDualPageEnabled
self.showsTableOfContents = showsTableOfContents
self.allowsHighlights = allowsHighlights
self.showsSettingsPanel = showsSettingsPanel
self.reflowableContentInsets = reflowableContentInsets
self.fixedContentInset = fixedContentInset
self.theme = theme
self.darkImageAdjustmentEnabled = darkImageAdjustmentEnabled
self.darkImageBlendRatio = max(0, min(0.35, darkImageBlendRatio))
self.fixedLayoutFit = fixedLayoutFit
self.fixedLayoutSpreadMode = fixedLayoutSpreadMode
self.textRenderingEngine = textRenderingEngine
self.onDemandChapterWindowSize = Self.normalizedChapterWindowSize(onDemandChapterWindowSize)
self.metadataParsingConcurrency = max(1, metadataParsingConcurrency)
self.jumpSessionPolicy = jumpSessionPolicy
self.allowedExternalURLSchemes = allowedExternalURLSchemes
self.requiresExternalLinkConfirmation = requiresExternalLinkConfirmation
self.allowsInspectableWebViews = allowsInspectableWebViews
self.enablesVerboseWebViewLogging = enablesVerboseWebViewLogging
self.trialPolicy = trialPolicy
}
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
}
var chapterWindowRadius: Int {
onDemandChapterWindowSize / 2
}
}
extension RDEPUBReaderConfiguration {
func makePreferences(safeAreaInsets: UIEdgeInsets = .zero) -> RDEPUBPreferences {
// Use the larger of reflowableContentInsets and safeAreaInsets for each edge
// to prevent content from being hidden under Dynamic Island / home indicator.
// Falls back to the key-window safe area when the caller has no laid-out view.
let resolvedSafeAreaInsets = RDEPUBSafeArea.resolve(safeAreaInsets)
let safeInsets = UIEdgeInsets(
top: max(reflowableContentInsets.top, resolvedSafeAreaInsets.top),
left: max(reflowableContentInsets.left, resolvedSafeAreaInsets.left),
bottom: max(reflowableContentInsets.bottom, resolvedSafeAreaInsets.bottom),
right: max(reflowableContentInsets.right, resolvedSafeAreaInsets.right)
)
return RDEPUBPreferences(
fontSize: fontSize,
lineHeightMultiple: lineHeightMultiple,
reflowableContentInsets: safeInsets,
fixedContentInset: fixedContentInset,
numberOfColumns: numberOfColumns,
columnGap: columnGap,
themeBackgroundColor: theme.themeBackgroundColorCSS,
themeTextColor: theme.themeTextColorCSS,
fixedBackgroundColor: theme.themeBackgroundColorCSS,
fixedLayoutFit: fixedLayoutFit,
fixedLayoutSpreadMode: fixedLayoutSpreadMode
)
}
}