mastodon-app-ufficiale-ipho.../Mastodon/Scene/Compose/TableViewCell/ComposeStatusContentTableVi...

173 lines
6.9 KiB
Swift
Raw Normal View History

//
// ComposeStatusContentTableViewCell.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-6-28.
//
import os.log
import UIKit
import Combine
2021-07-22 13:34:24 +02:00
import MetaTextKit
2021-07-19 11:12:45 +02:00
import UITextView_Placeholder
import MastodonAsset
import MastodonLocalization
import MastodonUI
2021-09-29 10:27:35 +02:00
protocol ComposeStatusContentTableViewCellDelegate: AnyObject {
func composeStatusContentTableViewCell(_ cell: ComposeStatusContentTableViewCell, textViewShouldBeginEditing textView: UITextView) -> Bool
}
final class ComposeStatusContentTableViewCell: UITableViewCell {
let logger = Logger(subsystem: "ComposeStatusContentTableViewCell", category: "View")
2021-07-19 11:12:45 +02:00
var disposeBag = Set<AnyCancellable>()
2021-09-29 10:27:35 +02:00
weak var delegate: ComposeStatusContentTableViewCellDelegate?
let statusView = StatusView()
let statusContentWarningEditorView = StatusContentWarningEditorView()
let textEditorViewContainerView = UIView()
static let metaTextViewTag: Int = 333
let metaText: MetaText = {
let metaText = MetaText()
metaText.textView.backgroundColor = .clear
metaText.textView.isScrollEnabled = false
metaText.textView.keyboardType = .twitter
metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment
2021-06-29 10:41:58 +02:00
metaText.textView.textContainer.lineFragmentPadding = 10 // leading inset
metaText.textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
metaText.textView.attributedPlaceholder = {
var attributes = metaText.textAttributes
attributes[.foregroundColor] = Asset.Colors.Label.secondary.color
return NSAttributedString(
string: L10n.Scene.Compose.contentInputPlaceholder,
attributes: attributes
)
}()
2021-07-23 13:10:27 +02:00
metaText.paragraphStyle = {
2021-06-30 09:43:33 +02:00
let style = NSMutableParagraphStyle()
style.lineSpacing = 5
style.paragraphSpacing = 0
2021-06-30 09:43:33 +02:00
return style
}()
metaText.textAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)),
.foregroundColor: Asset.Colors.Label.primary.color,
]
metaText.linkAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)),
2022-06-02 11:31:23 +02:00
.foregroundColor: Asset.Colors.brand.color,
2021-06-30 09:43:33 +02:00
]
return metaText
}()
// output
let contentWarningContent = PassthroughSubject<String, Never>()
override func prepareForReuse() {
super.prepareForReuse()
metaText.delegate = nil
metaText.textView.delegate = nil
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension ComposeStatusContentTableViewCell {
private func _init() {
2021-06-29 10:41:58 +02:00
selectionStyle = .none
layer.zPosition = 999
backgroundColor = .clear
preservesSuperviewLayoutMargins = true
let containerStackView = UIStackView()
containerStackView.axis = .vertical
containerStackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(containerStackView)
NSLayoutConstraint.activate([
containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
])
containerStackView.preservesSuperviewLayoutMargins = true
containerStackView.addArrangedSubview(statusContentWarningEditorView)
statusContentWarningEditorView.setContentHuggingPriority(.required - 1, for: .vertical)
let statusContainerView = UIView()
statusContainerView.preservesSuperviewLayoutMargins = true
containerStackView.addArrangedSubview(statusContainerView)
statusView.translatesAutoresizingMaskIntoConstraints = false
statusContainerView.addSubview(statusView)
NSLayoutConstraint.activate([
statusView.topAnchor.constraint(equalTo: statusContainerView.topAnchor, constant: 20),
statusView.leadingAnchor.constraint(equalTo: statusContainerView.leadingAnchor),
statusView.trailingAnchor.constraint(equalTo: statusContainerView.trailingAnchor),
statusView.bottomAnchor.constraint(equalTo: statusContainerView.bottomAnchor),
])
statusView.setup(style: .composeStatusAuthor)
containerStackView.addArrangedSubview(textEditorViewContainerView)
metaText.textView.translatesAutoresizingMaskIntoConstraints = false
textEditorViewContainerView.addSubview(metaText.textView)
NSLayoutConstraint.activate([
metaText.textView.topAnchor.constraint(equalTo: textEditorViewContainerView.topAnchor),
metaText.textView.leadingAnchor.constraint(equalTo: textEditorViewContainerView.layoutMarginsGuide.leadingAnchor),
metaText.textView.trailingAnchor.constraint(equalTo: textEditorViewContainerView.layoutMarginsGuide.trailingAnchor),
metaText.textView.bottomAnchor.constraint(equalTo: textEditorViewContainerView.bottomAnchor),
metaText.textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 64).priority(.defaultHigh),
])
statusContentWarningEditorView.textView.delegate = self
}
}
// MARK: - UITextViewDelegate
extension ComposeStatusContentTableViewCell: UITextViewDelegate {
2021-09-29 10:27:35 +02:00
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
return delegate?.composeStatusContentTableViewCell(self, textViewShouldBeginEditing: textView) ?? true
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
switch textView {
case statusContentWarningEditorView.textView:
// disable input line break
guard text != "\n" else { return false }
return true
default:
assertionFailure()
return true
}
}
func textViewDidChange(_ textView: UITextView) {
2021-07-19 11:12:45 +02:00
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): text: \(textView.text ?? "<nil>")")
guard textView === statusContentWarningEditorView.textView else { return }
// replace line break with space
// needs check input state to prevent break the IME
if textView.markedTextRange == nil {
textView.text = textView.text.replacingOccurrences(of: "\n", with: " ")
}
contentWarningContent.send(textView.text)
}
}