2020-12-10 02:44:06 +00:00
|
|
|
// Copyright © 2020 Metabolist. All rights reserved.
|
|
|
|
|
|
|
|
import Combine
|
|
|
|
import Foundation
|
|
|
|
import Mastodon
|
|
|
|
import ServiceLayer
|
|
|
|
|
|
|
|
public final class CompositionViewModel: ObservableObject {
|
2020-12-18 00:17:17 +00:00
|
|
|
public let id = Id()
|
2020-12-19 06:30:19 +00:00
|
|
|
public var isPosted = false
|
2020-12-18 00:17:17 +00:00
|
|
|
@Published public var text = ""
|
2020-12-19 06:30:19 +00:00
|
|
|
@Published public private(set) var attachmentViewModels = [CompositionAttachmentViewModel]()
|
2020-12-16 01:39:38 +00:00
|
|
|
@Published public private(set) var isPostable = false
|
2020-12-10 02:44:06 +00:00
|
|
|
@Published public private(set) var identification: Identification
|
2020-12-17 06:48:06 +00:00
|
|
|
@Published public private(set) var attachmentUpload: AttachmentUpload?
|
2020-12-10 02:44:06 +00:00
|
|
|
|
2020-12-16 01:39:38 +00:00
|
|
|
private let eventsSubject: PassthroughSubject<Event, Never>
|
2020-12-17 06:48:06 +00:00
|
|
|
private var cancellables = Set<AnyCancellable>()
|
2020-12-16 01:39:38 +00:00
|
|
|
|
2020-12-18 00:17:17 +00:00
|
|
|
init(identification: Identification,
|
2020-12-16 01:39:38 +00:00
|
|
|
identificationPublisher: AnyPublisher<Identification, Never>,
|
|
|
|
eventsSubject: PassthroughSubject<Event, Never>) {
|
2020-12-10 02:44:06 +00:00
|
|
|
self.identification = identification
|
2020-12-16 01:39:38 +00:00
|
|
|
self.eventsSubject = eventsSubject
|
2020-12-10 02:44:06 +00:00
|
|
|
identificationPublisher.assign(to: &$identification)
|
2020-12-18 00:17:17 +00:00
|
|
|
$text.map { !$0.isEmpty }.removeDuplicates().assign(to: &$isPostable)
|
2020-12-16 01:39:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public extension CompositionViewModel {
|
2020-12-18 00:17:17 +00:00
|
|
|
typealias Id = UUID
|
|
|
|
|
2020-12-16 01:39:38 +00:00
|
|
|
enum Event {
|
|
|
|
case insertAfter(CompositionViewModel)
|
|
|
|
case presentMediaPicker(CompositionViewModel)
|
2020-12-17 06:48:06 +00:00
|
|
|
case error(Error)
|
|
|
|
}
|
|
|
|
|
2020-12-19 06:30:19 +00:00
|
|
|
func components(inReplyToId: Status.Id?) -> StatusComponents {
|
|
|
|
StatusComponents(
|
|
|
|
inReplyToId: inReplyToId,
|
|
|
|
text: text,
|
|
|
|
mediaIds: attachmentViewModels.map(\.attachment.id))
|
2020-12-16 01:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func presentMediaPicker() {
|
|
|
|
eventsSubject.send(.presentMediaPicker(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
func insert() {
|
|
|
|
eventsSubject.send(.insertAfter(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
func attach(itemProvider: NSItemProvider) {
|
2020-12-17 06:48:06 +00:00
|
|
|
let progress = Progress(totalUnitCount: 1)
|
|
|
|
|
|
|
|
MediaProcessingService.dataAndMimeType(itemProvider: itemProvider)
|
|
|
|
.flatMap { [weak self] data, mimeType -> AnyPublisher<Attachment, Error> in
|
|
|
|
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
|
|
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
self.attachmentUpload = AttachmentUpload(progress: progress, data: data, mimeType: mimeType)
|
|
|
|
}
|
|
|
|
|
|
|
|
return self.identification.service.uploadAttachment(data: data, mimeType: mimeType, progress: progress)
|
|
|
|
}
|
|
|
|
.print()
|
2020-12-19 06:30:19 +00:00
|
|
|
.receive(on: DispatchQueue.main)
|
2020-12-17 06:48:06 +00:00
|
|
|
.sink { [weak self] in
|
2020-12-19 06:30:19 +00:00
|
|
|
self?.attachmentUpload = nil
|
2020-12-17 06:48:06 +00:00
|
|
|
|
|
|
|
if case let .failure(error) = $0 {
|
|
|
|
self?.eventsSubject.send(.error(error))
|
|
|
|
}
|
|
|
|
} receiveValue: { [weak self] in
|
2020-12-19 06:30:19 +00:00
|
|
|
self?.attachmentViewModels.append(CompositionAttachmentViewModel(attachment: $0))
|
2020-12-17 06:48:06 +00:00
|
|
|
}
|
|
|
|
.store(in: &cancellables)
|
2020-12-10 02:44:06 +00:00
|
|
|
}
|
2020-12-19 06:30:19 +00:00
|
|
|
|
|
|
|
func attachmentViewModel(indexPath: IndexPath) -> CompositionAttachmentViewModel {
|
|
|
|
attachmentViewModels[indexPath.item]
|
|
|
|
}
|
2020-12-10 02:44:06 +00:00
|
|
|
}
|