2021-03-11 08:41:27 +01:00
|
|
|
//
|
|
|
|
// ComposeStatusSection.swift
|
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by MainasuK Cirno on 2021-3-11.
|
|
|
|
//
|
|
|
|
|
2021-03-12 07:18:07 +01:00
|
|
|
import UIKit
|
|
|
|
import Combine
|
|
|
|
import CoreData
|
|
|
|
import CoreDataStack
|
2021-03-12 12:25:28 +01:00
|
|
|
import TwitterTextEditor
|
2021-03-18 08:16:35 +01:00
|
|
|
import AlamofireImage
|
2021-03-11 08:41:27 +01:00
|
|
|
|
|
|
|
enum ComposeStatusSection: Equatable, Hashable {
|
|
|
|
case repliedTo
|
|
|
|
case status
|
2021-03-17 11:09:38 +01:00
|
|
|
case attachment
|
2021-03-11 08:41:27 +01:00
|
|
|
}
|
2021-03-12 07:18:07 +01:00
|
|
|
|
|
|
|
extension ComposeStatusSection {
|
|
|
|
enum ComposeKind {
|
2021-03-15 06:42:46 +01:00
|
|
|
case post
|
|
|
|
case reply(repliedToStatusObjectID: NSManagedObjectID)
|
2021-03-12 07:18:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension ComposeStatusSection {
|
|
|
|
static func tableViewDiffableDataSource(
|
|
|
|
for tableView: UITableView,
|
|
|
|
dependency: NeedsDependency,
|
|
|
|
managedObjectContext: NSManagedObjectContext,
|
2021-03-12 12:25:28 +01:00
|
|
|
composeKind: ComposeKind,
|
2021-03-18 08:16:35 +01:00
|
|
|
textEditorViewTextAttributesDelegate: TextEditorViewTextAttributesDelegate,
|
|
|
|
composeStatusAttachmentTableViewCellDelegate: ComposeStatusAttachmentTableViewCellDelegate
|
2021-03-12 07:18:07 +01:00
|
|
|
) -> UITableViewDiffableDataSource<ComposeStatusSection, ComposeStatusItem> {
|
2021-03-18 08:16:35 +01:00
|
|
|
UITableViewDiffableDataSource<ComposeStatusSection, ComposeStatusItem>(tableView: tableView) { [weak textEditorViewTextAttributesDelegate, weak composeStatusAttachmentTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in
|
2021-03-12 07:18:07 +01:00
|
|
|
switch item {
|
2021-03-15 06:42:46 +01:00
|
|
|
case .replyTo(let repliedToStatusObjectID):
|
2021-03-12 07:18:07 +01:00
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ComposeRepliedToTootContentTableViewCell.self), for: indexPath) as! ComposeRepliedToTootContentTableViewCell
|
|
|
|
// TODO:
|
|
|
|
return cell
|
2021-03-16 04:23:19 +01:00
|
|
|
case .input(let replyToTootObjectID, let attribute):
|
2021-03-17 11:09:38 +01:00
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ComposeStatusContentTableViewCell.self), for: indexPath) as! ComposeStatusContentTableViewCell
|
2021-03-18 10:33:07 +01:00
|
|
|
cell.textEditorView.text = attribute.composeContent.value ?? ""
|
2021-03-12 07:18:07 +01:00
|
|
|
managedObjectContext.perform {
|
|
|
|
guard let replyToTootObjectID = replyToTootObjectID,
|
|
|
|
let replyTo = managedObjectContext.object(with: replyToTootObjectID) as? Toot else {
|
|
|
|
cell.statusView.headerContainerStackView.isHidden = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cell.statusView.headerContainerStackView.isHidden = false
|
|
|
|
cell.statusView.headerInfoLabel.text = "[TODO] \(replyTo.author.displayName)"
|
|
|
|
}
|
2021-03-12 08:57:58 +01:00
|
|
|
ComposeStatusSection.configure(cell: cell, attribute: attribute)
|
2021-03-12 12:25:28 +01:00
|
|
|
cell.textEditorView.textAttributesDelegate = textEditorViewTextAttributesDelegate
|
2021-03-12 07:18:07 +01:00
|
|
|
// self size input cell
|
|
|
|
cell.composeContent
|
2021-03-18 10:33:07 +01:00
|
|
|
.removeDuplicates()
|
2021-03-12 07:18:07 +01:00
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { text in
|
|
|
|
tableView.beginUpdates()
|
|
|
|
tableView.endUpdates()
|
2021-03-18 10:33:07 +01:00
|
|
|
// bind input data
|
|
|
|
attribute.composeContent.value = text
|
2021-03-12 07:18:07 +01:00
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
|
|
|
return cell
|
2021-03-17 11:09:38 +01:00
|
|
|
case .attachment(let attachmentService):
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ComposeStatusAttachmentTableViewCell.self), for: indexPath) as! ComposeStatusAttachmentTableViewCell
|
2021-03-18 10:33:07 +01:00
|
|
|
cell.attachmentContainerView.descriptionTextView.text = attachmentService.description.value
|
2021-03-18 08:16:35 +01:00
|
|
|
cell.delegate = composeStatusAttachmentTableViewCellDelegate
|
|
|
|
attachmentService.imageData
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { imageData in
|
|
|
|
guard let imageData = imageData,
|
|
|
|
let image = UIImage(data: imageData) else {
|
|
|
|
let placeholder = UIImage.placeholder(
|
|
|
|
size: cell.attachmentContainerView.previewImageView.frame.size,
|
|
|
|
color: Asset.Colors.Background.systemGroupedBackground.color
|
|
|
|
)
|
|
|
|
.af.imageRounded(
|
|
|
|
withCornerRadius: AttachmentContainerView.containerViewCornerRadius
|
|
|
|
)
|
|
|
|
cell.attachmentContainerView.previewImageView.image = placeholder
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
|
|
|
|
cell.attachmentContainerView.previewImageView.image = image
|
|
|
|
.af.imageAspectScaled(toFill: cell.attachmentContainerView.previewImageView.frame.size)
|
|
|
|
.af.imageRounded(withCornerRadius: AttachmentContainerView.containerViewCornerRadius)
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
|
|
|
attachmentService.error
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { error in
|
|
|
|
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
|
|
|
|
cell.attachmentContainerView.emptyStateView.isHidden = error == nil
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-18 10:33:07 +01:00
|
|
|
NotificationCenter.default.publisher(
|
|
|
|
for: UITextView.textDidChangeNotification,
|
|
|
|
object: cell.attachmentContainerView.descriptionTextView
|
|
|
|
)
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { notification in
|
|
|
|
guard let textField = notification.object as? UITextView else { return }
|
|
|
|
let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
attachmentService.description.value = text
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-17 11:09:38 +01:00
|
|
|
return cell
|
2021-03-12 07:18:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension ComposeStatusSection {
|
2021-03-12 08:57:58 +01:00
|
|
|
static func configure(
|
2021-03-17 11:09:38 +01:00
|
|
|
cell: ComposeStatusContentTableViewCell,
|
2021-03-16 04:23:19 +01:00
|
|
|
attribute: ComposeStatusItem.ComposeStatusAttribute
|
2021-03-12 07:18:07 +01:00
|
|
|
) {
|
2021-03-12 08:57:58 +01:00
|
|
|
// set avatar
|
2021-03-12 07:18:07 +01:00
|
|
|
attribute.avatarURL
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { avatarURL in
|
|
|
|
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: avatarURL))
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-12 08:57:58 +01:00
|
|
|
// set display name and username
|
2021-03-12 07:18:07 +01:00
|
|
|
Publishers.CombineLatest(
|
|
|
|
attribute.displayName.eraseToAnyPublisher(),
|
|
|
|
attribute.username.eraseToAnyPublisher()
|
|
|
|
)
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { displayName, username in
|
|
|
|
cell.statusView.nameLabel.text = displayName
|
|
|
|
cell.statusView.usernameLabel.text = username
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-12 08:57:58 +01:00
|
|
|
|
|
|
|
// bind compose content
|
|
|
|
cell.composeContent
|
|
|
|
.map { $0 as String? }
|
|
|
|
.assign(to: \.value, on: attribute.composeContent)
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-12 07:18:07 +01:00
|
|
|
}
|
|
|
|
}
|