2020-12-10 02:44:06 +00:00
|
|
|
// Copyright © 2020 Metabolist. All rights reserved.
|
|
|
|
|
|
|
|
import Combine
|
|
|
|
import Kingfisher
|
|
|
|
import UIKit
|
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
final class CompositionView: UIView {
|
2020-12-10 02:44:06 +00:00
|
|
|
let avatarImageView = UIImageView()
|
|
|
|
let textView = UITextView()
|
2020-12-17 06:48:06 +00:00
|
|
|
let attachmentUploadView = AttachmentUploadView()
|
2020-12-19 06:30:19 +00:00
|
|
|
let attachmentsCollectionView: UICollectionView
|
2020-12-10 02:44:06 +00:00
|
|
|
|
|
|
|
private var compositionConfiguration: CompositionContentConfiguration
|
|
|
|
private var cancellables = Set<AnyCancellable>()
|
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
private lazy var attachmentsDataSource: CompositionAttachmentsDataSource = {
|
|
|
|
CompositionAttachmentsDataSource(
|
|
|
|
collectionView: attachmentsCollectionView,
|
|
|
|
viewModelProvider: compositionConfiguration.viewModel.attachmentViewModel(indexPath:))
|
|
|
|
}()
|
|
|
|
|
2020-12-10 02:44:06 +00:00
|
|
|
init(configuration: CompositionContentConfiguration) {
|
|
|
|
self.compositionConfiguration = configuration
|
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
let itemSize = NSCollectionLayoutSize(
|
|
|
|
widthDimension: .fractionalWidth(0.2),
|
|
|
|
heightDimension: .fractionalHeight(1.0))
|
|
|
|
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
|
|
|
let groupSize = NSCollectionLayoutSize(
|
|
|
|
widthDimension: .fractionalWidth(1.0),
|
|
|
|
heightDimension: .fractionalWidth(0.2))
|
|
|
|
let group = NSCollectionLayoutGroup.horizontal(
|
|
|
|
layoutSize: groupSize,
|
|
|
|
subitems: [item])
|
|
|
|
|
|
|
|
group.interItemSpacing = .fixed(.defaultSpacing)
|
|
|
|
|
|
|
|
let section = NSCollectionLayoutSection(group: group)
|
|
|
|
let attachmentsLayout = UICollectionViewCompositionalLayout(section: section)
|
|
|
|
attachmentsCollectionView = UICollectionView(frame: .zero, collectionViewLayout: attachmentsLayout)
|
|
|
|
|
2020-12-10 02:44:06 +00:00
|
|
|
super.init(frame: .zero)
|
|
|
|
|
|
|
|
initialSetup()
|
|
|
|
applyCompositionConfiguration()
|
|
|
|
}
|
|
|
|
|
|
|
|
@available(*, unavailable)
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
fatalError("init(coder:) has not been implemented")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension CompositionView: UIContentView {
|
|
|
|
var configuration: UIContentConfiguration {
|
|
|
|
get { compositionConfiguration }
|
|
|
|
set {
|
|
|
|
guard let compositionConfiguration = newValue as? CompositionContentConfiguration else { return }
|
|
|
|
|
|
|
|
self.compositionConfiguration = compositionConfiguration
|
|
|
|
|
|
|
|
applyCompositionConfiguration()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 01:39:38 +00:00
|
|
|
extension CompositionView: UITextViewDelegate {
|
|
|
|
func textViewDidChange(_ textView: UITextView) {
|
2020-12-18 00:17:17 +00:00
|
|
|
compositionConfiguration.viewModel.text = textView.text
|
2020-12-16 01:39:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-10 02:44:06 +00:00
|
|
|
private extension CompositionView {
|
2020-12-19 06:30:19 +00:00
|
|
|
static let attachmentUploadViewHeight: CGFloat = 100
|
2020-12-17 06:48:06 +00:00
|
|
|
|
2020-12-10 02:44:06 +00:00
|
|
|
func initialSetup() {
|
|
|
|
addSubview(avatarImageView)
|
|
|
|
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
avatarImageView.layer.cornerRadius = .avatarDimension / 2
|
|
|
|
avatarImageView.clipsToBounds = true
|
|
|
|
|
|
|
|
let stackView = UIStackView()
|
|
|
|
|
|
|
|
addSubview(stackView)
|
|
|
|
stackView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
stackView.axis = .vertical
|
|
|
|
|
|
|
|
stackView.addArrangedSubview(textView)
|
|
|
|
textView.isScrollEnabled = false
|
|
|
|
textView.adjustsFontForContentSizeCategory = true
|
|
|
|
textView.font = .preferredFont(forTextStyle: .body)
|
|
|
|
textView.textContainer.lineFragmentPadding = 0
|
2020-12-16 01:39:38 +00:00
|
|
|
textView.inputAccessoryView = CompositionInputAccessoryView(viewModel: compositionConfiguration.viewModel)
|
|
|
|
textView.inputAccessoryView?.sizeToFit()
|
|
|
|
textView.delegate = self
|
2020-12-10 02:44:06 +00:00
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
stackView.addArrangedSubview(attachmentsCollectionView)
|
|
|
|
attachmentsCollectionView.dataSource = attachmentsDataSource
|
2020-12-17 06:48:06 +00:00
|
|
|
|
|
|
|
stackView.addArrangedSubview(attachmentUploadView)
|
|
|
|
|
2020-12-12 00:41:37 +00:00
|
|
|
let constraints = [
|
2020-12-10 02:44:06 +00:00
|
|
|
avatarImageView.heightAnchor.constraint(equalToConstant: .avatarDimension),
|
2020-12-12 00:41:37 +00:00
|
|
|
avatarImageView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
2020-12-10 02:44:06 +00:00
|
|
|
avatarImageView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
|
|
|
avatarImageView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
|
|
|
avatarImageView.bottomAnchor.constraint(lessThanOrEqualTo: readableContentGuide.bottomAnchor),
|
|
|
|
stackView.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: .defaultSpacing),
|
|
|
|
stackView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
|
|
|
stackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
2020-12-17 06:48:06 +00:00
|
|
|
stackView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor),
|
2020-12-19 06:30:19 +00:00
|
|
|
attachmentsCollectionView.heightAnchor.constraint(
|
|
|
|
equalTo: attachmentsCollectionView.widthAnchor,
|
|
|
|
multiplier: 1 / 4),
|
|
|
|
attachmentUploadView.heightAnchor.constraint(equalToConstant: Self.attachmentUploadViewHeight)
|
2020-12-12 00:41:37 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
for constraint in constraints {
|
|
|
|
constraint.priority = .justBelowMax
|
|
|
|
}
|
|
|
|
|
|
|
|
NSLayoutConstraint.activate(constraints)
|
2020-12-10 02:44:06 +00:00
|
|
|
|
|
|
|
compositionConfiguration.viewModel.$identification.map(\.identity.image)
|
|
|
|
.sink { [weak self] in self?.avatarImageView.kf.setImage(with: $0) }
|
|
|
|
.store(in: &cancellables)
|
2020-12-17 06:48:06 +00:00
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
compositionConfiguration.viewModel.$attachmentViewModels
|
|
|
|
.sink { [weak self] in
|
|
|
|
self?.attachmentsDataSource.apply([$0.map(\.attachment)].snapshot())
|
|
|
|
self?.attachmentsCollectionView.isHidden = $0.isEmpty
|
|
|
|
}
|
|
|
|
.store(in: &cancellables)
|
|
|
|
|
2020-12-17 06:48:06 +00:00
|
|
|
compositionConfiguration.viewModel.$attachmentUpload
|
|
|
|
.sink { [weak self] in self?.attachmentUploadView.attachmentUpload = $0 }
|
|
|
|
.store(in: &cancellables)
|
2020-12-10 02:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func applyCompositionConfiguration() {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|