metatext/ViewModels/Sources/ViewModels/CompositionViewModel.swift

85 lines
2.9 KiB
Swift
Raw Normal View History

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
}