feat: improve epub reader controls and annotations
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import UIKit
|
||||
|
||||
final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDelegate {
|
||||
|
||||
private let quote: String
|
||||
private let initialNote: String?
|
||||
private let onSave: (String?) -> Void
|
||||
private let textView = UITextView()
|
||||
private let countLabel = UILabel()
|
||||
|
||||
init(quote: String, initialNote: String?, onSave: @escaping (String?) -> Void) {
|
||||
self.quote = quote
|
||||
self.initialNote = initialNote
|
||||
self.onSave = onSave
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
title = "写注释"
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = UIColor(red: 0.975, green: 0.965, blue: 0.935, alpha: 1)
|
||||
configureNavigation()
|
||||
configureContent()
|
||||
updateCount()
|
||||
DispatchQueue.main.async { [weak self] in self?.textView.becomeFirstResponder() }
|
||||
}
|
||||
|
||||
private func configureNavigation() {
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(
|
||||
title: "取消", style: .plain, target: self, action: #selector(cancelAction)
|
||||
)
|
||||
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.titleTextAttributes = [
|
||||
.foregroundColor: UIColor(red: 0.08, green: 0.10, blue: 0.14, alpha: 1),
|
||||
.font: UIFont.systemFont(ofSize: 17, weight: .semibold)
|
||||
]
|
||||
}
|
||||
|
||||
private func configureContent() {
|
||||
let quoteCard = UIView()
|
||||
let rail = UIView()
|
||||
let quoteLabel = UILabel()
|
||||
let inputCard = UIView()
|
||||
|
||||
[quoteCard, rail, quoteLabel, inputCard, textView, countLabel].forEach {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
view.addSubview(quoteCard)
|
||||
quoteCard.addSubview(rail)
|
||||
quoteCard.addSubview(quoteLabel)
|
||||
view.addSubview(inputCard)
|
||||
inputCard.addSubview(textView)
|
||||
inputCard.addSubview(countLabel)
|
||||
|
||||
quoteCard.backgroundColor = UIColor.white.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)
|
||||
|
||||
inputCard.backgroundColor = .white
|
||||
inputCard.layer.cornerRadius = 18
|
||||
inputCard.layer.shadowColor = UIColor.black.cgColor
|
||||
inputCard.layer.shadowOpacity = 0.06
|
||||
inputCard.layer.shadowRadius = 18
|
||||
inputCard.layer.shadowOffset = CGSize(width: 0, height: 6)
|
||||
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.backgroundColor = .clear
|
||||
textView.accessibilityIdentifier = "epub.reader.annotation.editor"
|
||||
countLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: .regular)
|
||||
countLabel.textColor = .secondaryLabel
|
||||
countLabel.textAlignment = .right
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
quoteCard.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
|
||||
quoteCard.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
|
||||
quoteCard.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
|
||||
rail.leadingAnchor.constraint(equalTo: quoteCard.leadingAnchor, constant: 16),
|
||||
rail.topAnchor.constraint(equalTo: quoteCard.topAnchor, constant: 16),
|
||||
rail.bottomAnchor.constraint(equalTo: quoteCard.bottomAnchor, constant: -16),
|
||||
rail.widthAnchor.constraint(equalToConstant: 4),
|
||||
quoteLabel.leadingAnchor.constraint(equalTo: rail.trailingAnchor, constant: 14),
|
||||
quoteLabel.trailingAnchor.constraint(equalTo: quoteCard.trailingAnchor, constant: -18),
|
||||
quoteLabel.topAnchor.constraint(equalTo: quoteCard.topAnchor, constant: 16),
|
||||
quoteLabel.bottomAnchor.constraint(equalTo: quoteCard.bottomAnchor, constant: -16),
|
||||
|
||||
inputCard.topAnchor.constraint(equalTo: quoteCard.bottomAnchor, constant: 18),
|
||||
inputCard.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
|
||||
inputCard.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
|
||||
inputCard.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor, constant: -16),
|
||||
inputCard.heightAnchor.constraint(greaterThanOrEqualToConstant: 210),
|
||||
textView.topAnchor.constraint(equalTo: inputCard.topAnchor, constant: 14),
|
||||
textView.leadingAnchor.constraint(equalTo: inputCard.leadingAnchor, constant: 14),
|
||||
textView.trailingAnchor.constraint(equalTo: inputCard.trailingAnchor, constant: -14),
|
||||
textView.bottomAnchor.constraint(equalTo: countLabel.topAnchor, constant: -8),
|
||||
countLabel.leadingAnchor.constraint(equalTo: inputCard.leadingAnchor, constant: 16),
|
||||
countLabel.trailingAnchor.constraint(equalTo: inputCard.trailingAnchor, constant: -16),
|
||||
countLabel.bottomAnchor.constraint(equalTo: inputCard.bottomAnchor, constant: -12)
|
||||
])
|
||||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
if textView.text.count > 1000 {
|
||||
textView.text = String(textView.text.prefix(1000))
|
||||
}
|
||||
updateCount()
|
||||
}
|
||||
|
||||
private func updateCount() {
|
||||
countLabel.text = "\(textView.text.count)/1000"
|
||||
}
|
||||
|
||||
@objc private func cancelAction() {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
@objc private func saveAction() {
|
||||
let note = textView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
onSave(note.isEmpty ? nil : note)
|
||||
dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user