完善阅读器主题与批注界面
This commit is contained in:
parent
adc24d3f36
commit
6a0a1223b1
@ -16,7 +16,6 @@ enum IDs {
|
||||
static let readerToc = "epub.reader.toc"
|
||||
static let readerBookmarks = "epub.reader.bookmarks"
|
||||
static let readerHighlights = "epub.reader.highlights"
|
||||
static let readerAddHighlight = "epub.reader.add-highlight"
|
||||
static let readerSettings = "epub.reader.settings"
|
||||
static let readerTocPanel = "epub.reader.toc.panel"
|
||||
static let readerTocTable = "epub.reader.toc.table"
|
||||
|
||||
@ -7,15 +7,6 @@ final class ReaderAnnotationExtendedTests: XCTestCase {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
func testBottomToolbarHasAddHighlightButton() {
|
||||
app.launchAndOpenSampleBook()
|
||||
app.waitForReader()
|
||||
app.showReaderChromeIfNeeded()
|
||||
|
||||
let addHighlightButton = app.buttons[IDs.readerAddHighlight]
|
||||
XCTAssertTrue(addHighlightButton.waitForExistence(timeout: 5), "底部工具栏标注按钮未出现")
|
||||
}
|
||||
|
||||
func testBottomToolbarHasHighlightsButton() {
|
||||
app.launchAndOpenSampleBook()
|
||||
app.waitForReader()
|
||||
@ -32,8 +23,7 @@ final class ReaderAnnotationExtendedTests: XCTestCase {
|
||||
|
||||
XCTAssertTrue(app.buttons[IDs.readerToc].waitForExistence(timeout: 5), "目录按钮未出现")
|
||||
XCTAssertTrue(app.buttons[IDs.readerBookmarks].exists, "书签按钮未出现")
|
||||
XCTAssertTrue(app.buttons[IDs.readerHighlights].exists, "高亮按钮未出现")
|
||||
XCTAssertTrue(app.buttons[IDs.readerAddHighlight].exists, "标注按钮未出现")
|
||||
XCTAssertTrue(app.buttons[IDs.readerHighlights].exists, "标注列表按钮未出现")
|
||||
XCTAssertTrue(app.buttons[IDs.readerSettings].exists, "设置按钮未出现")
|
||||
}
|
||||
|
||||
|
||||
@ -38,25 +38,6 @@ final class ToolbarStateTests: XCTestCase {
|
||||
app.waitForDemoReaderState(timeout: 5, description: "reader=opened") { $0.isOpened }
|
||||
}
|
||||
|
||||
func testAddHighlightButtonDisabledWithoutSelection() throws {
|
||||
app.launchAndOpenSampleBook()
|
||||
app.waitForReader(timeout: 12)
|
||||
|
||||
app.showReaderChromeIfNeeded()
|
||||
|
||||
let addHighlightButton = app.buttons[IDs.readerAddHighlight]
|
||||
XCTAssertTrue(addHighlightButton.waitForExistence(timeout: 3), "标注按钮应存在")
|
||||
|
||||
let beforeState = app.waitForDemoReaderState(timeout: 3, description: "初始高亮数") { $0.highlights != nil }
|
||||
let highlightsBefore = beforeState.highlights ?? 0
|
||||
|
||||
addHighlightButton.tap()
|
||||
|
||||
let afterState = app.waitForDemoReaderState(timeout: 3, description: "点击后的高亮数") { $0.highlights != nil }
|
||||
let highlightsAfter = afterState.highlights ?? 0
|
||||
XCTAssertEqual(highlightsAfter, highlightsBefore, "无选区时点击标注按钮不应创建标注")
|
||||
}
|
||||
|
||||
func testPageCurlSwipeNavigation() throws {
|
||||
app.launchAndOpenSampleBook(displayType: "pagecurl")
|
||||
app.waitForReader(timeout: 12)
|
||||
|
||||
@ -136,6 +136,9 @@ struct RDEPUBStyleSheetComposer {
|
||||
private static func darkCSS(style: RDEPUBTextRenderStyle) -> String {
|
||||
let background = style.backgroundColor?.rd_cssString ?? "rgba(0, 0, 0, 1.000)"
|
||||
let text = style.textColor?.rd_cssString ?? "rgba(255, 255, 255, 1.000)"
|
||||
// Keep the established dark-theme compatibility rules, but explicitly
|
||||
// clear the universal background that they would otherwise apply to image
|
||||
// attachments when converted into attributed strings by DTCoreText.
|
||||
return RDEPUBAssetRepository.string(for: .wxReadDarkCSS) + "\n\n" + """
|
||||
html, body {
|
||||
background: \(background) !important;
|
||||
@ -144,6 +147,9 @@ struct RDEPUBStyleSheetComposer {
|
||||
a {
|
||||
color: \(text) !important;
|
||||
}
|
||||
img, video {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
@ -4,12 +4,14 @@ final class RDEPUBNotePopupCoordinator {
|
||||
|
||||
static func present(
|
||||
_ note: RDEPUBResolvedNote,
|
||||
theme: RDEPUBReaderTheme,
|
||||
from controller: UIViewController,
|
||||
onReturnToSource: (() -> Void)? = nil,
|
||||
onOpenNoteLocation: (() -> Void)? = nil
|
||||
) {
|
||||
let popup = RDEPUBNotePopupViewController(
|
||||
note: note,
|
||||
theme: theme,
|
||||
onReturnToSource: onReturnToSource,
|
||||
onOpenNoteLocation: onOpenNoteLocation
|
||||
)
|
||||
|
||||
@ -3,6 +3,7 @@ import UIKit
|
||||
final class RDEPUBNotePopupViewController: UIViewController {
|
||||
|
||||
private let note: RDEPUBResolvedNote
|
||||
private let theme: RDEPUBReaderTheme
|
||||
private let onReturnToSource: (() -> Void)?
|
||||
private let onOpenNoteLocation: (() -> Void)?
|
||||
|
||||
@ -11,10 +12,12 @@ final class RDEPUBNotePopupViewController: UIViewController {
|
||||
|
||||
init(
|
||||
note: RDEPUBResolvedNote,
|
||||
theme: RDEPUBReaderTheme,
|
||||
onReturnToSource: (() -> Void)? = nil,
|
||||
onOpenNoteLocation: (() -> Void)? = nil
|
||||
) {
|
||||
self.note = note
|
||||
self.theme = theme
|
||||
self.onReturnToSource = onReturnToSource
|
||||
self.onOpenNoteLocation = onOpenNoteLocation
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
@ -28,7 +31,7 @@ final class RDEPUBNotePopupViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .systemBackground
|
||||
view.backgroundColor = theme.toolBackgroundColor
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
barButtonSystemItem: .done,
|
||||
target: self,
|
||||
@ -83,8 +86,8 @@ final class RDEPUBNotePopupViewController: UIViewController {
|
||||
var configuration = UIButton.Configuration.filled()
|
||||
configuration.cornerStyle = .medium
|
||||
configuration.title = title
|
||||
configuration.baseBackgroundColor = .secondarySystemBackground
|
||||
configuration.baseForegroundColor = .label
|
||||
configuration.baseBackgroundColor = theme.toolControlTextColor.withAlphaComponent(0.10)
|
||||
configuration.baseForegroundColor = theme.toolControlTextColor
|
||||
button.configuration = configuration
|
||||
if title == "返回原文" {
|
||||
button.accessibilityIdentifier = "epub.reader.note.return"
|
||||
@ -103,7 +106,7 @@ final class RDEPUBNotePopupViewController: UIViewController {
|
||||
<style>
|
||||
body {
|
||||
font: -apple-system-body;
|
||||
color: #1f1f1f;
|
||||
color: \(theme.themeTextColorCSS);
|
||||
line-height: 1.55;
|
||||
}
|
||||
a { color: #3b6ea8; }
|
||||
|
||||
@ -4,13 +4,20 @@ final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDe
|
||||
|
||||
private let quote: String
|
||||
private let initialNote: String?
|
||||
private let theme: RDEPUBReaderTheme
|
||||
private let onSave: (String?) -> Void
|
||||
private let textView = UITextView()
|
||||
private let countLabel = UILabel()
|
||||
|
||||
init(quote: String, initialNote: String?, onSave: @escaping (String?) -> Void) {
|
||||
init(
|
||||
quote: String,
|
||||
initialNote: String?,
|
||||
theme: RDEPUBReaderTheme,
|
||||
onSave: @escaping (String?) -> Void
|
||||
) {
|
||||
self.quote = quote
|
||||
self.initialNote = initialNote
|
||||
self.theme = theme
|
||||
self.onSave = onSave
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
title = "写注释"
|
||||
@ -22,7 +29,7 @@ final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDe
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = UIColor(red: 0.975, green: 0.965, blue: 0.935, alpha: 1)
|
||||
view.backgroundColor = theme.toolBackgroundColor
|
||||
configureNavigation()
|
||||
configureContent()
|
||||
updateCount()
|
||||
@ -36,9 +43,9 @@ final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDe
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
title: "保存", style: .done, target: self, action: #selector(saveAction)
|
||||
)
|
||||
navigationController?.navigationBar.tintColor = UIColor(red: 0.10, green: 0.34, blue: 0.78, alpha: 1)
|
||||
navigationController?.navigationBar.tintColor = .systemBlue
|
||||
navigationController?.navigationBar.titleTextAttributes = [
|
||||
.foregroundColor: UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1),
|
||||
.foregroundColor: theme.toolControlTextColor,
|
||||
.font: UIFont.systemFont(ofSize: 17, weight: .semibold)
|
||||
]
|
||||
}
|
||||
@ -59,16 +66,16 @@ final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDe
|
||||
inputCard.addSubview(textView)
|
||||
inputCard.addSubview(countLabel)
|
||||
|
||||
quoteCard.backgroundColor = UIColor.white.withAlphaComponent(0.78)
|
||||
quoteCard.backgroundColor = theme.contentBackgroundColor.withAlphaComponent(0.78)
|
||||
quoteCard.layer.cornerRadius = 16
|
||||
rail.backgroundColor = UIColor(red: 0.94, green: 0.63, blue: 0.18, alpha: 1)
|
||||
rail.layer.cornerRadius = 2
|
||||
quoteLabel.text = quote
|
||||
quoteLabel.numberOfLines = 5
|
||||
quoteLabel.font = UIFont.systemFont(ofSize: 16)
|
||||
quoteLabel.textColor = UIColor(red: 0.19, green: 0.20, blue: 0.23, alpha: 1)
|
||||
quoteLabel.textColor = theme.contentTextColor.withAlphaComponent(0.85)
|
||||
|
||||
inputCard.backgroundColor = .white
|
||||
inputCard.backgroundColor = theme.contentBackgroundColor
|
||||
inputCard.layer.cornerRadius = 18
|
||||
inputCard.layer.shadowColor = UIColor.black.cgColor
|
||||
inputCard.layer.shadowOpacity = 0.06
|
||||
@ -77,7 +84,7 @@ final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDe
|
||||
textView.text = initialNote
|
||||
textView.delegate = self
|
||||
textView.font = UIFont.systemFont(ofSize: 17)
|
||||
textView.textColor = UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1)
|
||||
textView.textColor = theme.contentTextColor
|
||||
textView.backgroundColor = .clear
|
||||
textView.accessibilityIdentifier = "epub.reader.annotation.editor"
|
||||
countLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: .regular)
|
||||
|
||||
@ -8,6 +8,7 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
|
||||
var onShowHighlights: (() -> Void)?
|
||||
|
||||
@available(*, deprecated, message: "Use the text selection menu to create annotations.")
|
||||
var onAddHighlight: (() -> Void)?
|
||||
|
||||
var onShowSettings: (() -> Void)?
|
||||
@ -25,9 +26,8 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
|
||||
private let bookmarksButton = RDEPUBReaderTintButton(type: .system)
|
||||
|
||||
private let highlightsButton = RDEPUBReaderTintButton(type: .system)
|
||||
|
||||
private let addHighlightButton = RDEPUBReaderTintButton(type: .system)
|
||||
/// 标注列表入口:查看全书已有划线 / 注释
|
||||
private let annotationListButton = RDEPUBReaderTintButton(type: .system)
|
||||
|
||||
private let settingsButton = RDEPUBReaderTintButton(type: .system)
|
||||
|
||||
@ -39,8 +39,7 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.addArrangedSubview(chapterButton)
|
||||
stackView.addArrangedSubview(bookmarksButton)
|
||||
stackView.addArrangedSubview(highlightsButton)
|
||||
stackView.addArrangedSubview(addHighlightButton)
|
||||
stackView.addArrangedSubview(annotationListButton)
|
||||
stackView.addArrangedSubview(settingsButton)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
@ -52,23 +51,20 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
|
||||
configureButton(chapterButton, systemName: "list.bullet", fallbackTitle: "目录")
|
||||
configureButton(bookmarksButton, systemName: "bookmark", fallbackTitle: "书签")
|
||||
configureButton(highlightsButton, systemName: "note.text", fallbackTitle: "标注")
|
||||
configureButton(addHighlightButton, systemName: "highlighter", fallbackTitle: "标注")
|
||||
configureButton(annotationListButton, systemName: "note.text", 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"
|
||||
annotationListButton.accessibilityIdentifier = "epub.reader.highlights"
|
||||
settingsButton.accessibilityIdentifier = "epub.reader.settings"
|
||||
|
||||
[chapterButton, bookmarksButton, highlightsButton, addHighlightButton, settingsButton].forEach { button in
|
||||
[chapterButton, bookmarksButton, annotationListButton, 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)
|
||||
annotationListButton.addTarget(self, action: #selector(annotationListAction), for: .touchUpInside)
|
||||
settingsButton.addTarget(self, action: #selector(settingsAction), for: .touchUpInside)
|
||||
}
|
||||
|
||||
@ -82,20 +78,21 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
|
||||
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)
|
||||
[chapterButton, bookmarksButton, annotationListButton, settingsButton].forEach { button in
|
||||
button.tintColor = theme.toolControlTextColor
|
||||
button.setTitleColor(theme.toolControlTextColor, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
func setAddHighlightEnabled(_ isEnabled: Bool) {
|
||||
addHighlightButton.isEnabled = isEnabled
|
||||
addHighlightButton.alpha = isEnabled ? 1 : 0.45
|
||||
func setHighlightsEnabled(_ isEnabled: Bool) {
|
||||
annotationListButton.isEnabled = isEnabled
|
||||
annotationListButton.alpha = isEnabled ? 1 : 0.45
|
||||
}
|
||||
|
||||
func setHighlightsEnabled(_ isEnabled: Bool) {
|
||||
highlightsButton.isEnabled = isEnabled
|
||||
highlightsButton.alpha = isEnabled ? 1 : 0.45
|
||||
@available(*, deprecated, message: "Use the text selection menu to create annotations.")
|
||||
func setAddHighlightEnabled(_ isEnabled: Bool) {
|
||||
// The built-in toolbar no longer exposes this action. Keep the method so
|
||||
// custom toolbar integrations compiled against previous SDKs remain valid.
|
||||
}
|
||||
|
||||
func setBookmarksEnabled(_ isEnabled: Bool) {
|
||||
@ -110,8 +107,7 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
) {
|
||||
chapterButton.isHidden = !showsTableOfContents
|
||||
bookmarksButton.isHidden = false
|
||||
highlightsButton.isHidden = !allowsHighlights
|
||||
addHighlightButton.isHidden = !allowsHighlights
|
||||
annotationListButton.isHidden = !allowsHighlights
|
||||
settingsButton.isHidden = !showsSettingsPanel
|
||||
}
|
||||
|
||||
@ -132,14 +128,10 @@ final class RDEPUBReaderBottomToolView: RDEPUBReaderToolView, RDEPUBReaderBottom
|
||||
onShowBookmarks?()
|
||||
}
|
||||
|
||||
@objc private func highlightsAction() {
|
||||
@objc private func annotationListAction() {
|
||||
onShowHighlights?()
|
||||
}
|
||||
|
||||
@objc private func highlightAction() {
|
||||
onAddHighlight?()
|
||||
}
|
||||
|
||||
@objc private func settingsAction() {
|
||||
onShowSettings?()
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ final class RDEPUBReaderChapterListController: UITableViewController {
|
||||
tableView.accessibilityIdentifier = "epub.reader.toc.table"
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
|
||||
tableView.tableFooterView = UIView(frame: .zero)
|
||||
tableView.backgroundColor = theme.contentBackgroundColor
|
||||
tableView.backgroundColor = theme.toolBackgroundColor
|
||||
navigationController?.navigationBar.tintColor = theme.toolControlTextColor
|
||||
navigationController?.navigationBar.barTintColor = theme.toolBackgroundColor
|
||||
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: theme.toolControlTextColor]
|
||||
@ -46,7 +46,7 @@ final class RDEPUBReaderChapterListController: UITableViewController {
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let item = items[indexPath.row]
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||
cell.backgroundColor = theme.contentBackgroundColor
|
||||
cell.backgroundColor = theme.toolBackgroundColor
|
||||
cell.textLabel?.numberOfLines = 2
|
||||
cell.textLabel?.text = item.title
|
||||
if isCurrentItem(item) {
|
||||
|
||||
@ -154,6 +154,7 @@ extension RDEPUBReaderController: RDEPUBTextContentViewDelegate {
|
||||
|
||||
RDEPUBNotePopupCoordinator.present(
|
||||
note,
|
||||
theme: configuration.theme,
|
||||
from: self,
|
||||
onReturnToSource: { [weak self] in
|
||||
guard let self, let sourceLocation = note.sourceLocation else { return }
|
||||
|
||||
@ -130,10 +130,6 @@ extension RDEPUBReaderController {
|
||||
runtime.presentHighlightsManager()
|
||||
}
|
||||
|
||||
func presentAnnotationCreation() {
|
||||
runtime.presentAnnotationCreation()
|
||||
}
|
||||
|
||||
func handleSelectionMenuAction(_ action: RDEPUBAnnotationMenuAction, selection: RDEPUBSelection?) {
|
||||
runtime.handleSelectionMenuAction(action, selection: selection)
|
||||
}
|
||||
|
||||
@ -68,15 +68,15 @@ final class RDEPUBReaderHighlightsViewController: UITableViewController {
|
||||
let highlight = filteredHighlights[indexPath.row]
|
||||
|
||||
cell.backgroundColor = .clear
|
||||
cell.contentView.backgroundColor = UIColor.white.withAlphaComponent(0.76)
|
||||
cell.contentView.backgroundColor = theme.contentBackgroundColor.withAlphaComponent(0.76)
|
||||
cell.contentView.layer.cornerRadius = 14
|
||||
cell.contentView.layer.masksToBounds = true
|
||||
cell.textLabel?.textColor = UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1)
|
||||
cell.textLabel?.textColor = theme.contentTextColor
|
||||
cell.textLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
|
||||
cell.textLabel?.numberOfLines = 2
|
||||
cell.textLabel?.text = titleText(for: highlight)
|
||||
|
||||
cell.detailTextLabel?.textColor = UIColor(red: 0.34, green: 0.36, blue: 0.40, alpha: 1)
|
||||
cell.detailTextLabel?.textColor = theme.contentTextColor.withAlphaComponent(0.65)
|
||||
cell.detailTextLabel?.font = UIFont.systemFont(ofSize: 12)
|
||||
cell.detailTextLabel?.numberOfLines = 3
|
||||
cell.detailTextLabel?.text = detailText(for: highlight)
|
||||
@ -113,10 +113,10 @@ final class RDEPUBReaderHighlightsViewController: UITableViewController {
|
||||
}
|
||||
|
||||
private func applyTheme() {
|
||||
tableView.backgroundColor = UIColor(red: 0.975, green: 0.965, blue: 0.935, alpha: 1)
|
||||
navigationController?.navigationBar.tintColor = UIColor(red: 0.10, green: 0.34, blue: 0.78, alpha: 1)
|
||||
tableView.backgroundColor = theme.toolBackgroundColor
|
||||
navigationController?.navigationBar.tintColor = .systemBlue
|
||||
navigationController?.navigationBar.barTintColor = tableView.backgroundColor
|
||||
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1)]
|
||||
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: theme.toolControlTextColor]
|
||||
navigationController?.navigationBar.accessibilityIdentifier = "epub.reader.highlights.navbar"
|
||||
}
|
||||
|
||||
@ -243,15 +243,15 @@ final class RDEPUBReaderBookmarksViewController: UITableViewController {
|
||||
let bookmark = bookmarks[indexPath.row]
|
||||
|
||||
cell.backgroundColor = .clear
|
||||
cell.contentView.backgroundColor = UIColor.white.withAlphaComponent(0.76)
|
||||
cell.contentView.backgroundColor = theme.contentBackgroundColor.withAlphaComponent(0.76)
|
||||
cell.contentView.layer.cornerRadius = 14
|
||||
cell.contentView.layer.masksToBounds = true
|
||||
cell.textLabel?.textColor = UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1)
|
||||
cell.textLabel?.textColor = theme.contentTextColor
|
||||
cell.textLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
|
||||
cell.textLabel?.numberOfLines = 2
|
||||
cell.textLabel?.text = titleText(for: bookmark)
|
||||
|
||||
cell.detailTextLabel?.textColor = UIColor(red: 0.34, green: 0.36, blue: 0.40, alpha: 1)
|
||||
cell.detailTextLabel?.textColor = theme.contentTextColor.withAlphaComponent(0.65)
|
||||
cell.detailTextLabel?.font = UIFont.systemFont(ofSize: 12)
|
||||
cell.detailTextLabel?.numberOfLines = 3
|
||||
cell.detailTextLabel?.text = detailText(for: bookmark)
|
||||
@ -272,10 +272,10 @@ final class RDEPUBReaderBookmarksViewController: UITableViewController {
|
||||
}
|
||||
|
||||
private func applyTheme() {
|
||||
tableView.backgroundColor = UIColor(red: 0.975, green: 0.965, blue: 0.935, alpha: 1)
|
||||
navigationController?.navigationBar.tintColor = UIColor(red: 0.10, green: 0.34, blue: 0.78, alpha: 1)
|
||||
tableView.backgroundColor = theme.toolBackgroundColor
|
||||
navigationController?.navigationBar.tintColor = .systemBlue
|
||||
navigationController?.navigationBar.barTintColor = tableView.backgroundColor
|
||||
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1)]
|
||||
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: theme.toolControlTextColor]
|
||||
navigationController?.navigationBar.accessibilityIdentifier = "epub.reader.bookmarks.navbar"
|
||||
}
|
||||
|
||||
|
||||
@ -22,8 +22,8 @@ open class RDEPUBReaderToolView: UIView {
|
||||
}
|
||||
|
||||
open func apply(theme: RDEPUBReaderTheme) {
|
||||
backgroundColor = .white
|
||||
lineView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
|
||||
backgroundColor = theme.toolBackgroundColor
|
||||
lineView.backgroundColor = theme.toolLineColor
|
||||
}
|
||||
|
||||
open func lineFrame(in bounds: CGRect) -> CGRect {
|
||||
|
||||
@ -37,10 +37,13 @@ public protocol RDEPUBReaderBottomToolViewProtocol: AnyObject {
|
||||
/// 书签列表
|
||||
var onShowBookmarks: (() -> Void)? { get set }
|
||||
|
||||
/// 高亮列表
|
||||
/// 标注列表(已有划线 / 注释)
|
||||
var onShowHighlights: (() -> Void)? { get set }
|
||||
|
||||
/// 新增高亮 / 标注
|
||||
/// 新增高亮 / 标注。
|
||||
///
|
||||
/// 保留以兼容既有的自定义底部工具栏;内置工具栏不再提供对应入口。
|
||||
@available(*, deprecated, message: "Use the text selection menu to create annotations.")
|
||||
var onAddHighlight: (() -> Void)? { get set }
|
||||
|
||||
/// 设置面板
|
||||
@ -55,10 +58,13 @@ public protocol RDEPUBReaderBottomToolViewProtocol: AnyObject {
|
||||
/// 书签列表按钮是否可用
|
||||
func setBookmarksEnabled(_ isEnabled: Bool)
|
||||
|
||||
/// 新增高亮按钮是否可用(有选区时)
|
||||
/// 新增高亮按钮是否可用。
|
||||
///
|
||||
/// 保留以兼容既有的自定义底部工具栏;内置工具栏不再提供对应入口。
|
||||
@available(*, deprecated, message: "Use the text selection menu to create annotations.")
|
||||
func setAddHighlightEnabled(_ isEnabled: Bool)
|
||||
|
||||
/// 高亮列表按钮是否可用
|
||||
/// 标注列表按钮是否可用
|
||||
func setHighlightsEnabled(_ isEnabled: Bool)
|
||||
}
|
||||
|
||||
|
||||
@ -224,15 +224,6 @@ final class RDEPUBReaderAnnotationCoordinator {
|
||||
controller.present(navigationController, animated: true)
|
||||
}
|
||||
|
||||
func presentAnnotationCreation() {
|
||||
guard let controller else { return }
|
||||
guard controller.configuration.allowsHighlights,
|
||||
let currentSelection = controller.currentSelection else {
|
||||
return
|
||||
}
|
||||
presentAnnotationActionSheet(for: currentSelection)
|
||||
}
|
||||
|
||||
func handleHighlightMenuAction(_ action: RDEPUBExistingHighlightMenuAction, highlight: RDEPUBHighlight) {
|
||||
switch action {
|
||||
case .copy:
|
||||
@ -477,25 +468,6 @@ final class RDEPUBReaderAnnotationCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentAnnotationActionSheet(for selection: RDEPUBSelection) {
|
||||
guard let controller else { return }
|
||||
let alert = UIAlertController(title: "创建标注", message: nil, preferredStyle: .actionSheet)
|
||||
alert.addAction(UIAlertAction(title: "划线", style: .default) { [weak self] _ in
|
||||
self?.createAnnotation(from: selection, style: .underline)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "注释", style: .default) { [weak self] _ in
|
||||
self?.presentAnnotationNoteEditor(for: selection)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
||||
|
||||
if let popover = alert.popoverPresentationController {
|
||||
popover.sourceView = controller.bottomToolView
|
||||
popover.sourceRect = controller.bottomToolView.bounds
|
||||
}
|
||||
|
||||
controller.present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func createAnnotation(
|
||||
from selection: RDEPUBSelection,
|
||||
style: RDEPUBHighlightStyle,
|
||||
@ -533,6 +505,7 @@ final class RDEPUBReaderAnnotationCoordinator {
|
||||
let editor = RDEPUBAnnotationEditorViewController(
|
||||
quote: quote,
|
||||
initialNote: initialNote,
|
||||
theme: controller.configuration.theme,
|
||||
onSave: onSave
|
||||
)
|
||||
let navigationController = UINavigationController(rootViewController: editor)
|
||||
|
||||
@ -46,9 +46,6 @@ final class RDEPUBReaderChromeCoordinator: NSObject, UIAdaptivePresentationContr
|
||||
toolView.onShowHighlights = { [weak self] in
|
||||
self?.context.runtime?.presentHighlightsManager()
|
||||
}
|
||||
toolView.onAddHighlight = { [weak self] in
|
||||
self?.context.runtime?.presentAnnotationCreation()
|
||||
}
|
||||
toolView.onShowSettings = { [weak self] in
|
||||
self?.presentSettings()
|
||||
}
|
||||
@ -68,7 +65,6 @@ final class RDEPUBReaderChromeCoordinator: NSObject, UIAdaptivePresentationContr
|
||||
canToggleBookmark: controller.currentBookIdentifier != nil,
|
||||
hasBookmarkAtCurrentLocation: hasBookmarkAtCurrentLocation(),
|
||||
canShowBookmarks: !controller.activeBookmarks.isEmpty,
|
||||
canAddHighlight: controller.configuration.allowsHighlights && context.selectionState.hasSelection,
|
||||
canShowHighlights: controller.configuration.allowsHighlights && !controller.activeHighlights.isEmpty,
|
||||
showsTableOfContents: controller.configuration.showsTableOfContents,
|
||||
allowsHighlights: controller.configuration.allowsHighlights,
|
||||
@ -93,7 +89,6 @@ final class RDEPUBReaderChromeCoordinator: NSObject, UIAdaptivePresentationContr
|
||||
showsSettingsPanel: state.showsSettingsPanel
|
||||
)
|
||||
controller.bottomToolView.setBookmarksEnabled(state.canShowBookmarks)
|
||||
controller.bottomToolView.setAddHighlightEnabled(state.canAddHighlight)
|
||||
controller.bottomToolView.setHighlightsEnabled(state.canShowHighlights)
|
||||
}
|
||||
|
||||
@ -261,11 +256,12 @@ private final class RDEPUBReaderSettingsPresentationController: UIPresentationCo
|
||||
let bounds = containerView.bounds
|
||||
let isLandscape = bounds.width > bounds.height
|
||||
if isLandscape {
|
||||
let safeBounds = bounds.inset(by: containerView.safeAreaInsets)
|
||||
let width = min(390, max(300, bounds.width * 0.32))
|
||||
let height = min(340, bounds.height - 32)
|
||||
let height = min(340, safeBounds.height - 32)
|
||||
return CGRect(
|
||||
x: bounds.maxX - width - 16,
|
||||
y: bounds.midY - height / 2,
|
||||
x: safeBounds.maxX - width - 16,
|
||||
y: safeBounds.midY - height / 2,
|
||||
width: width,
|
||||
height: height
|
||||
)
|
||||
|
||||
@ -139,11 +139,10 @@ final class RDEPUBReaderPaginationCoordinator {
|
||||
return
|
||||
}
|
||||
let restoreLocation = context.currentVisibleLocation() ?? context.persistenceLocation()
|
||||
if readerView.currentDisplayType == .pageCurl, readerView.currentPage >= 0 {
|
||||
readerView.transitionToPage(pageNum: readerView.currentPage, animated: false)
|
||||
} else {
|
||||
readerView.reloadData()
|
||||
}
|
||||
// pageCurl 不能走 transitionToPage(当前页, animated: false):同页无 fault 会被
|
||||
// 直接跳过,主题/暗色图片等外观变化不会重新 configure 可见页。reloadData
|
||||
// 会失效预加载缓存并重建翻页控制器,保证可见页与相邻页都按新配置重建。
|
||||
readerView.reloadData()
|
||||
if let restoreLocation {
|
||||
_ = context.restoreReadingLocation(restoreLocation)
|
||||
}
|
||||
|
||||
@ -252,10 +252,6 @@ final class RDEPUBReaderRuntime {
|
||||
annotationCoordinator.presentHighlightsManager()
|
||||
}
|
||||
|
||||
func presentAnnotationCreation() {
|
||||
annotationCoordinator.presentAnnotationCreation()
|
||||
}
|
||||
|
||||
func handleHighlightMenuAction(_ action: RDEPUBExistingHighlightMenuAction, highlight: RDEPUBHighlight) {
|
||||
annotationCoordinator.handleHighlightMenuAction(action, highlight: highlight)
|
||||
}
|
||||
|
||||
@ -8,8 +8,6 @@ struct RDEPUBReaderUIState {
|
||||
|
||||
let canShowBookmarks: Bool
|
||||
|
||||
let canAddHighlight: Bool
|
||||
|
||||
let canShowHighlights: Bool
|
||||
|
||||
let showsTableOfContents: Bool
|
||||
@ -25,7 +23,6 @@ extension RDEPUBReaderUIState {
|
||||
canToggleBookmark: false,
|
||||
hasBookmarkAtCurrentLocation: false,
|
||||
canShowBookmarks: false,
|
||||
canAddHighlight: false,
|
||||
canShowHighlights: false,
|
||||
showsTableOfContents: true,
|
||||
allowsHighlights: true,
|
||||
|
||||
@ -150,7 +150,7 @@ final class RDEPUBReaderSettingsViewController: UIViewController {
|
||||
handleView.widthAnchor.constraint(equalToConstant: 42),
|
||||
handleView.heightAnchor.constraint(equalToConstant: 5),
|
||||
closeButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
|
||||
closeButton.centerYAnchor.constraint(equalTo: handleView.centerYAnchor),
|
||||
closeButton.centerYAnchor.constraint(equalTo: handleView.centerYAnchor, constant: 20),
|
||||
closeButton.widthAnchor.constraint(equalToConstant: 32),
|
||||
closeButton.heightAnchor.constraint(equalToConstant: 32),
|
||||
|
||||
|
||||
@ -30,59 +30,41 @@ public struct RDEPUBReaderTheme: Equatable {
|
||||
self.toolLineColor = toolLineColor
|
||||
}
|
||||
|
||||
public static let light = RDEPUBReaderTheme(
|
||||
contentBackgroundColor: .white,
|
||||
contentTextColor: .black,
|
||||
toolBackgroundColor: .white,
|
||||
toolControlTextColor: .black,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
public static let light = preset(contentBackground: .white, text: .black)
|
||||
|
||||
public static let dark = preset(contentBackground: .black, text: .white)
|
||||
|
||||
public static let yellow = preset(
|
||||
contentBackground: UIColor(red: 0.89, green: 0.87, blue: 0.79, alpha: 1),
|
||||
text: .black
|
||||
)
|
||||
|
||||
public static let dark = RDEPUBReaderTheme(
|
||||
contentBackgroundColor: .black,
|
||||
contentTextColor: .white,
|
||||
toolBackgroundColor: .black,
|
||||
toolControlTextColor: .white,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
public static let green = preset(
|
||||
contentBackground: UIColor(red: 0.87, green: 0.91, blue: 0.82, alpha: 1),
|
||||
text: .black
|
||||
)
|
||||
|
||||
public static let yellow = RDEPUBReaderTheme(
|
||||
contentBackgroundColor: UIColor(red: 0.89, green: 0.87, blue: 0.79, alpha: 1),
|
||||
contentTextColor: .black,
|
||||
toolBackgroundColor: UIColor(red: 0.89, green: 0.87, blue: 0.79, alpha: 1),
|
||||
toolControlTextColor: .black,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
public static let pink = preset(
|
||||
contentBackground: UIColor(red: 1, green: 0.89, blue: 0.91, alpha: 1),
|
||||
text: .black
|
||||
)
|
||||
|
||||
public static let green = RDEPUBReaderTheme(
|
||||
contentBackgroundColor: UIColor(red: 0.87, green: 0.91, blue: 0.82, alpha: 1),
|
||||
contentTextColor: .black,
|
||||
toolBackgroundColor: UIColor(red: 0.87, green: 0.91, blue: 0.82, alpha: 1),
|
||||
toolControlTextColor: .black,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
public static let blue = preset(
|
||||
contentBackground: UIColor(red: 0.8, green: 0.84, blue: 0.89, alpha: 1),
|
||||
text: .black
|
||||
)
|
||||
|
||||
public static let pink = RDEPUBReaderTheme(
|
||||
contentBackgroundColor: UIColor(red: 1, green: 0.89, blue: 0.91, alpha: 1),
|
||||
contentTextColor: .black,
|
||||
toolBackgroundColor: UIColor(red: 1, green: 0.89, blue: 0.91, alpha: 1),
|
||||
toolControlTextColor: .black,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
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,
|
||||
toolBackgroundColor: UIColor(red: 0.8, green: 0.84, blue: 0.89, alpha: 1),
|
||||
toolControlTextColor: .black,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
)
|
||||
/// 工具条/弹出页统一用比正文背景稍深的底色(暗色主题稍亮),拉开层次对比。
|
||||
private static func preset(contentBackground: UIColor, text: UIColor) -> RDEPUBReaderTheme {
|
||||
RDEPUBReaderTheme(
|
||||
contentBackgroundColor: contentBackground,
|
||||
contentTextColor: text,
|
||||
toolBackgroundColor: contentBackground.rd_chromeShade,
|
||||
toolControlTextColor: text,
|
||||
toolControlBorderUnselectColor: UIColor.lightGray.withAlphaComponent(0.5),
|
||||
toolLineColor: UIColor.lightGray.withAlphaComponent(0.5)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension RDEPUBReaderTheme {
|
||||
|
||||
@ -28,4 +28,22 @@ extension UIColor {
|
||||
guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { return false }
|
||||
return (0.2126 * red + 0.7152 * green + 0.0722 * blue) < 0.4
|
||||
}
|
||||
|
||||
/// 工具条与弹出页的底色:比正文背景稍深一档以增加层次对比;
|
||||
/// 暗色背景无法更深,改为轻微提亮(浮层惯例)。
|
||||
var rd_chromeShade: UIColor {
|
||||
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
|
||||
guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { return self }
|
||||
if rd_isDarkBackground {
|
||||
let lift: CGFloat = 0.10
|
||||
return UIColor(
|
||||
red: red + (1 - red) * lift,
|
||||
green: green + (1 - green) * lift,
|
||||
blue: blue + (1 - blue) * lift,
|
||||
alpha: alpha
|
||||
)
|
||||
}
|
||||
let scale: CGFloat = 0.93
|
||||
return UIColor(red: red * scale, green: green * scale, blue: blue * scale, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user