- 新增 RDEPUBResourceDataProvider 解密钩子协议 + 访问登记表,收敛章节 HTML/ 图片/内联 CSS/脚注/封面/图片查看器/正文取图等读取点,scheme handler 对加密书 禁用流式分支;新增 RDEPUBDecryptingImageAttachment 解密 DTCoreText 图片附件; RDEPUBReaderDependencies.live(resourceDataProvider:) 便捷注入。明文书零影响。 - 试读墙:configuration.trialPolicy + delegate epubReaderTrialWallView/ DidReachTrialWall,UI 由宿主提供(RDEPUBReaderController+Trial)。 - 工具栏定制:RDEPUBReaderTop/BottomToolViewProtocol 协议 + dependencies 工厂注入, 内置栏已 conform,configureTopToolView 改协议类型。 - 朝向锁定:RDEPUBMetadata.orientation(OPF rendition:orientation 主, iBooks display-options 兜底)+ RDEPUBReaderController+Orientation 重写支持朝向、 打开后主动转向。 注:RDEPUBReaderController+LocationResolution / PaginationCoordinator 为本次改动前 即存在的工作区修改,一并纳入。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
147 lines
5.5 KiB
Swift
147 lines
5.5 KiB
Swift
import UIKit
|
|
|
|
final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottomToolViewProtocol {
|
|
|
|
var onShowTableOfContents: (() -> Void)?
|
|
|
|
var onShowBookmarks: (() -> Void)?
|
|
|
|
var onShowHighlights: (() -> Void)?
|
|
|
|
var onAddHighlight: (() -> Void)?
|
|
|
|
var onShowSettings: (() -> Void)?
|
|
|
|
private let stackView: UIStackView = {
|
|
let view = UIStackView()
|
|
view.axis = .horizontal
|
|
view.distribution = .fillEqually
|
|
view.alignment = .fill
|
|
view.spacing = 16
|
|
return view
|
|
}()
|
|
|
|
private let chapterButton = RDEPUBReaderTintButton(type: .system)
|
|
|
|
private let bookmarksButton = RDEPUBReaderTintButton(type: .system)
|
|
|
|
private let highlightsButton = RDEPUBReaderTintButton(type: .system)
|
|
|
|
private let addHighlightButton = RDEPUBReaderTintButton(type: .system)
|
|
|
|
private let settingsButton = RDEPUBReaderTintButton(type: .system)
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
accessibilityIdentifier = "epub.reader.bottomToolbar"
|
|
|
|
addSubview(stackView)
|
|
stackView.translatesAutoresizingMaskIntoConstraints = false
|
|
stackView.addArrangedSubview(chapterButton)
|
|
stackView.addArrangedSubview(bookmarksButton)
|
|
stackView.addArrangedSubview(highlightsButton)
|
|
stackView.addArrangedSubview(addHighlightButton)
|
|
stackView.addArrangedSubview(settingsButton)
|
|
|
|
NSLayoutConstraint.activate([
|
|
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
|
|
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
|
|
stackView.topAnchor.constraint(equalTo: topAnchor),
|
|
stackView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)
|
|
])
|
|
|
|
configureButton(chapterButton, systemName: "list.bullet", fallbackTitle: "目录")
|
|
configureButton(bookmarksButton, systemName: "bookmark", fallbackTitle: "书签")
|
|
configureButton(highlightsButton, systemName: "note.text", fallbackTitle: "批注")
|
|
configureButton(addHighlightButton, systemName: "highlighter", fallbackTitle: "标注")
|
|
configureButton(settingsButton, systemName: "textformat.size", fallbackTitle: "设置")
|
|
chapterButton.accessibilityIdentifier = "epub.reader.toc"
|
|
bookmarksButton.accessibilityIdentifier = "epub.reader.bookmarks"
|
|
highlightsButton.accessibilityIdentifier = "epub.reader.highlights"
|
|
addHighlightButton.accessibilityIdentifier = "epub.reader.add-highlight"
|
|
settingsButton.accessibilityIdentifier = "epub.reader.settings"
|
|
|
|
[chapterButton, bookmarksButton, highlightsButton, addHighlightButton, settingsButton].forEach { button in
|
|
button.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).isActive = true
|
|
}
|
|
|
|
chapterButton.addTarget(self, action: #selector(chapterAction), for: .touchUpInside)
|
|
bookmarksButton.addTarget(self, action: #selector(bookmarksAction), for: .touchUpInside)
|
|
highlightsButton.addTarget(self, action: #selector(highlightsAction), for: .touchUpInside)
|
|
addHighlightButton.addTarget(self, action: #selector(highlightAction), for: .touchUpInside)
|
|
settingsButton.addTarget(self, action: #selector(settingsAction), for: .touchUpInside)
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func lineFrame(in bounds: CGRect) -> CGRect {
|
|
CGRect(x: 0, y: 0, width: bounds.width, height: 0.5)
|
|
}
|
|
|
|
override func apply(theme: RDEPUBReaderTheme) {
|
|
super.apply(theme: theme)
|
|
[chapterButton, bookmarksButton, highlightsButton, addHighlightButton, settingsButton].forEach { button in
|
|
button.tintColor = .black
|
|
button.setTitleColor(.black, for: .normal)
|
|
}
|
|
}
|
|
|
|
func setAddHighlightEnabled(_ isEnabled: Bool) {
|
|
addHighlightButton.isEnabled = isEnabled
|
|
addHighlightButton.alpha = isEnabled ? 1 : 0.45
|
|
}
|
|
|
|
func setHighlightsEnabled(_ isEnabled: Bool) {
|
|
highlightsButton.isEnabled = isEnabled
|
|
highlightsButton.alpha = isEnabled ? 1 : 0.45
|
|
}
|
|
|
|
func setBookmarksEnabled(_ isEnabled: Bool) {
|
|
bookmarksButton.isEnabled = isEnabled
|
|
bookmarksButton.alpha = isEnabled ? 1 : 0.45
|
|
}
|
|
|
|
func updateVisibility(
|
|
showsTableOfContents: Bool,
|
|
allowsHighlights: Bool,
|
|
showsSettingsPanel: Bool
|
|
) {
|
|
chapterButton.isHidden = !showsTableOfContents
|
|
bookmarksButton.isHidden = false
|
|
highlightsButton.isHidden = !allowsHighlights
|
|
addHighlightButton.isHidden = !allowsHighlights
|
|
settingsButton.isHidden = !showsSettingsPanel
|
|
}
|
|
|
|
private func configureButton(_ button: UIButton, systemName: String, fallbackTitle: String) {
|
|
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
|
|
if #available(iOS 13.0, *), let image = UIImage(systemName: systemName) {
|
|
button.setImage(image.withRenderingMode(.alwaysTemplate), for: .normal)
|
|
} else {
|
|
button.setTitle(fallbackTitle, for: .normal)
|
|
}
|
|
}
|
|
|
|
@objc private func chapterAction() {
|
|
onShowTableOfContents?()
|
|
}
|
|
|
|
@objc private func bookmarksAction() {
|
|
onShowBookmarks?()
|
|
}
|
|
|
|
@objc private func highlightsAction() {
|
|
onShowHighlights?()
|
|
}
|
|
|
|
@objc private func highlightAction() {
|
|
onAddHighlight?()
|
|
}
|
|
|
|
@objc private func settingsAction() {
|
|
onShowSettings?()
|
|
}
|
|
}
|