import UIKit import SnapKit final class RDEPUBAnnotationEditorViewController: UIViewController, UITextViewDelegate { 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?, 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 = "写注释" } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = theme.toolBackgroundColor 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 = .systemBlue navigationController?.navigationBar.titleTextAttributes = [ .foregroundColor: theme.toolControlTextColor, .font: UIFont.systemFont(ofSize: 17, weight: .semibold) ] } private func configureContent() { let quoteCard = UIView() let rail = UIView() let quoteLabel = UILabel() let inputCard = UIView() view.addSubview(quoteCard) quoteCard.addSubview(rail) quoteCard.addSubview(quoteLabel) view.addSubview(inputCard) inputCard.addSubview(textView) inputCard.addSubview(countLabel) 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 = theme.contentTextColor.withAlphaComponent(0.85) inputCard.backgroundColor = theme.contentBackgroundColor 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 = theme.contentTextColor textView.backgroundColor = .clear textView.accessibilityIdentifier = "epub.reader.annotation.editor" countLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: .regular) countLabel.textColor = .secondaryLabel countLabel.textAlignment = .right quoteCard.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(20) make.horizontalEdges.equalToSuperview().inset(20) } rail.snp.makeConstraints { make in make.leading.equalToSuperview().offset(16) make.verticalEdges.equalToSuperview().inset(16) make.width.equalTo(4) } quoteLabel.snp.makeConstraints { make in make.leading.equalTo(rail.snp.trailing).offset(14) make.trailing.equalToSuperview().inset(18) make.verticalEdges.equalToSuperview().inset(16) } inputCard.snp.makeConstraints { make in make.top.equalTo(quoteCard.snp.bottom).offset(18) make.horizontalEdges.equalToSuperview().inset(20) make.bottom.equalTo(view.keyboardLayoutGuide.snp.top).offset(-16) make.height.greaterThanOrEqualTo(210) } textView.snp.makeConstraints { make in make.top.horizontalEdges.equalToSuperview().inset(14) make.bottom.equalTo(countLabel.snp.top).offset(-8) } countLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.bottom.equalToSuperview().inset(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) } }