mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-24 17:20:59 +00:00
wip
This commit is contained in:
parent
0c5a3de66b
commit
d86bbda4c2
11 changed files with 27 additions and 76 deletions
|
@ -1,9 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import GRDB
|
|
||||||
|
|
||||||
struct CompositionRecord: Codable, FetchableRecord, PersistableRecord {
|
|
||||||
let id: Composition.Id
|
|
||||||
let text: String
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
import GRDB
|
|
||||||
import Mastodon
|
|
||||||
|
|
||||||
public class Composition {
|
|
||||||
public let id: Id
|
|
||||||
@Published public var text: String
|
|
||||||
@Published public var attachments: [Attachment]
|
|
||||||
|
|
||||||
public init(id: Id, text: String) {
|
|
||||||
self.id = id
|
|
||||||
self.text = text
|
|
||||||
attachments = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension Composition {
|
|
||||||
typealias Id = UUID
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Composition {
|
|
||||||
convenience init(record: CompositionRecord) {
|
|
||||||
self.init(id: record.id, text: record.text)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import ViewModels
|
import ViewModels
|
||||||
|
|
||||||
final class NewStatusDataSource: UICollectionViewDiffableDataSource<Int, Composition.Id> {
|
final class NewStatusDataSource: UICollectionViewDiffableDataSource<Int, CompositionViewModel.Id> {
|
||||||
private let updateQueue =
|
private let updateQueue =
|
||||||
DispatchQueue(label: "com.metabolist.metatext.new-status-data-source.update-queue")
|
DispatchQueue(label: "com.metabolist.metatext.new-status-data-source.update-queue")
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ final class NewStatusDataSource: UICollectionViewDiffableDataSource<Int, Composi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func apply(_ snapshot: NSDiffableDataSourceSnapshot<Int, Composition.Id>,
|
override func apply(_ snapshot: NSDiffableDataSourceSnapshot<Int, CompositionViewModel.Id>,
|
||||||
animatingDifferences: Bool = true,
|
animatingDifferences: Bool = true,
|
||||||
completion: (() -> Void)? = nil) {
|
completion: (() -> Void)? = nil) {
|
||||||
updateQueue.async {
|
updateQueue.async {
|
||||||
|
|
|
@ -8,14 +8,13 @@ import Mastodon
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
public struct AppEnvironment {
|
public struct AppEnvironment {
|
||||||
public let uuid: () -> UUID
|
|
||||||
|
|
||||||
let session: URLSession
|
let session: URLSession
|
||||||
let webAuthSessionType: WebAuthSession.Type
|
let webAuthSessionType: WebAuthSession.Type
|
||||||
let keychain: Keychain.Type
|
let keychain: Keychain.Type
|
||||||
let userDefaults: UserDefaults
|
let userDefaults: UserDefaults
|
||||||
let userNotificationClient: UserNotificationClient
|
let userNotificationClient: UserNotificationClient
|
||||||
let reduceMotion: () -> Bool
|
let reduceMotion: () -> Bool
|
||||||
|
let uuid: () -> UUID
|
||||||
let inMemoryContent: Bool
|
let inMemoryContent: Bool
|
||||||
let fixtureDatabase: IdentityDatabase?
|
let fixtureDatabase: IdentityDatabase?
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import DB
|
|
||||||
|
|
||||||
public typealias Composition = DB.Composition
|
|
|
@ -212,8 +212,8 @@ public extension IdentityService {
|
||||||
progress: progress)
|
progress: progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func post(compositions: [Composition]) -> AnyPublisher<Never, Error> {
|
// func post(compositions: [Composition]) -> AnyPublisher<Never, Error> {
|
||||||
fatalError()
|
// fatalError()
|
||||||
// guard let composition = compositions.first else { fatalError() }
|
// guard let composition = compositions.first else { fatalError() }
|
||||||
|
|
||||||
// guard let attachment = composition.attachments.first else { fatalError() }
|
// guard let attachment = composition.attachments.first else { fatalError() }
|
||||||
|
@ -235,7 +235,7 @@ public extension IdentityService {
|
||||||
// return mastodonAPIClient.request(StatusEndpoint.post(components))
|
// return mastodonAPIClient.request(StatusEndpoint.post(components))
|
||||||
// .ignoreOutput()
|
// .ignoreOutput()
|
||||||
// .eraseToAnyPublisher()
|
// .eraseToAnyPublisher()
|
||||||
}
|
// }
|
||||||
|
|
||||||
func service(timeline: Timeline) -> TimelineService {
|
func service(timeline: Timeline) -> TimelineService {
|
||||||
TimelineService(timeline: timeline, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
TimelineService(timeline: timeline, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
||||||
|
|
|
@ -61,7 +61,7 @@ class NewStatusViewController: UICollectionViewController {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
let oldSnapshot = self.dataSource.snapshot()
|
let oldSnapshot = self.dataSource.snapshot()
|
||||||
let newSnapshot = [$0.map(\.composition.id)].snapshot()
|
let newSnapshot = [$0.map(\.id)].snapshot()
|
||||||
let diff = newSnapshot.itemIdentifiers.difference(from: oldSnapshot.itemIdentifiers)
|
let diff = newSnapshot.itemIdentifiers.difference(from: oldSnapshot.itemIdentifiers)
|
||||||
|
|
||||||
self.dataSource.apply(newSnapshot) {
|
self.dataSource.apply(newSnapshot) {
|
||||||
|
@ -75,11 +75,8 @@ class NewStatusViewController: UICollectionViewController {
|
||||||
|
|
||||||
// Invalidate the collection view layout on anything that could change the height of a cell
|
// Invalidate the collection view layout on anything that could change the height of a cell
|
||||||
viewModel.$compositionViewModels
|
viewModel.$compositionViewModels
|
||||||
.flatMap { Publishers.MergeMany($0.map(\.composition.$text)) }
|
.flatMap { Publishers.MergeMany($0.map(\.objectWillChange)) }
|
||||||
.map { _ in () }
|
.receive(on: DispatchQueue.main)
|
||||||
.merge(with: viewModel.$compositionViewModels
|
|
||||||
.flatMap { Publishers.MergeMany($0.map(\.objectWillChange)) }
|
|
||||||
.map { _ in () })
|
|
||||||
.sink { [weak self] in self?.collectionView.collectionViewLayout.invalidateLayout() }
|
.sink { [weak self] in self?.collectionView.collectionViewLayout.invalidateLayout() }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
@ -89,6 +86,7 @@ class NewStatusViewController: UICollectionViewController {
|
||||||
|
|
||||||
viewModel.$alertItem
|
viewModel.$alertItem
|
||||||
.compactMap { $0 }
|
.compactMap { $0 }
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] in self?.present(alertItem: $0) }
|
.sink { [weak self] in self?.present(alertItem: $0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class CompositionViewModel: ObservableObject {
|
public final class CompositionViewModel: ObservableObject {
|
||||||
public let composition: Composition
|
public let id = Id()
|
||||||
|
@Published public var text = ""
|
||||||
|
@Published public private(set) var attachments = [Attachment]()
|
||||||
@Published public private(set) var isPostable = false
|
@Published public private(set) var isPostable = false
|
||||||
@Published public private(set) var identification: Identification
|
@Published public private(set) var identification: Identification
|
||||||
@Published public private(set) var attachmentUpload: AttachmentUpload?
|
@Published public private(set) var attachmentUpload: AttachmentUpload?
|
||||||
|
@ -14,19 +16,19 @@ public final class CompositionViewModel: ObservableObject {
|
||||||
private let eventsSubject: PassthroughSubject<Event, Never>
|
private let eventsSubject: PassthroughSubject<Event, Never>
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init(composition: Composition,
|
init(identification: Identification,
|
||||||
identification: Identification,
|
|
||||||
identificationPublisher: AnyPublisher<Identification, Never>,
|
identificationPublisher: AnyPublisher<Identification, Never>,
|
||||||
eventsSubject: PassthroughSubject<Event, Never>) {
|
eventsSubject: PassthroughSubject<Event, Never>) {
|
||||||
self.composition = composition
|
|
||||||
self.identification = identification
|
self.identification = identification
|
||||||
self.eventsSubject = eventsSubject
|
self.eventsSubject = eventsSubject
|
||||||
identificationPublisher.assign(to: &$identification)
|
identificationPublisher.assign(to: &$identification)
|
||||||
composition.$text.map { !$0.isEmpty }.removeDuplicates().assign(to: &$isPostable)
|
$text.map { !$0.isEmpty }.removeDuplicates().assign(to: &$isPostable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension CompositionViewModel {
|
public extension CompositionViewModel {
|
||||||
|
typealias Id = UUID
|
||||||
|
|
||||||
enum Event {
|
enum Event {
|
||||||
case insertAfter(CompositionViewModel)
|
case insertAfter(CompositionViewModel)
|
||||||
case presentMediaPicker(CompositionViewModel)
|
case presentMediaPicker(CompositionViewModel)
|
||||||
|
@ -70,7 +72,7 @@ public extension CompositionViewModel {
|
||||||
self?.eventsSubject.send(.error(error))
|
self?.eventsSubject.send(.error(error))
|
||||||
}
|
}
|
||||||
} receiveValue: { [weak self] in
|
} receiveValue: { [weak self] in
|
||||||
self?.composition.attachments.append($0)
|
self?.attachments.append($0)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import ServiceLayer
|
|
||||||
|
|
||||||
public typealias Composition = ServiceLayer.Composition
|
|
|
@ -67,21 +67,20 @@ public extension NewStatusViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
func post() {
|
func post() {
|
||||||
identification.service.post(compositions: compositionViewModels.map(\.composition))
|
// identification.service.post(compositions: compositionViewModels.map(\.composition))
|
||||||
.receive(on: DispatchQueue.main)
|
// .receive(on: DispatchQueue.main)
|
||||||
.handleEvents(
|
// .handleEvents(
|
||||||
receiveSubscription: { [weak self] _ in self?.loading = true },
|
// receiveSubscription: { [weak self] _ in self?.loading = true },
|
||||||
receiveCompletion: { [weak self] _ in self?.loading = false })
|
// receiveCompletion: { [weak self] _ in self?.loading = false })
|
||||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
// .assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||||
.sink { _ in }
|
// .sink { _ in }
|
||||||
.store(in: &cancellables)
|
// .store(in: &cancellables)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension NewStatusViewModel {
|
private extension NewStatusViewModel {
|
||||||
func newCompositionViewModel() -> CompositionViewModel {
|
func newCompositionViewModel() -> CompositionViewModel {
|
||||||
CompositionViewModel(
|
CompositionViewModel(
|
||||||
composition: .init(id: environment.uuid(), text: ""),
|
|
||||||
identification: identification,
|
identification: identification,
|
||||||
identificationPublisher: $identification.eraseToAnyPublisher(),
|
identificationPublisher: $identification.eraseToAnyPublisher(),
|
||||||
eventsSubject: itemEventsSubject)
|
eventsSubject: itemEventsSubject)
|
||||||
|
|
|
@ -43,7 +43,7 @@ extension CompositionView: UIContentView {
|
||||||
|
|
||||||
extension CompositionView: UITextViewDelegate {
|
extension CompositionView: UITextViewDelegate {
|
||||||
func textViewDidChange(_ textView: UITextView) {
|
func textViewDidChange(_ textView: UITextView) {
|
||||||
compositionConfiguration.viewModel.composition.text = textView.text
|
compositionConfiguration.viewModel.text = textView.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue