Refactoring
This commit is contained in:
parent
f3e1baecaa
commit
a07d25c80b
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import DB
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
import MastodonAPI
|
||||||
|
|
||||||
|
public struct ContextService: CollectionService {
|
||||||
|
public let sections: AnyPublisher<[[CollectionItem]], Error>
|
||||||
|
public let navigationService: NavigationService
|
||||||
|
public let nextPageMaxIDs: AnyPublisher<String?, Never> = Empty().eraseToAnyPublisher()
|
||||||
|
public let title: String? = nil
|
||||||
|
public var contextParentID: String? { statusID }
|
||||||
|
|
||||||
|
private let statusID: String
|
||||||
|
private let mastodonAPIClient: MastodonAPIClient
|
||||||
|
private let contentDatabase: ContentDatabase
|
||||||
|
|
||||||
|
init(statusID: String, mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) {
|
||||||
|
self.statusID = statusID
|
||||||
|
self.mastodonAPIClient = mastodonAPIClient
|
||||||
|
self.contentDatabase = contentDatabase
|
||||||
|
sections = contentDatabase.contextObservation(parentID: statusID)
|
||||||
|
navigationService = NavigationService(
|
||||||
|
status: nil,
|
||||||
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
|
contentDatabase: contentDatabase)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func request(maxID: String?, minID: String?) -> AnyPublisher<Never, Error> {
|
||||||
|
mastodonAPIClient.request(StatusEndpoint.status(id: statusID))
|
||||||
|
.flatMap(contentDatabase.insert(status:))
|
||||||
|
.merge(with: mastodonAPIClient.request(ContextEndpoint.context(id: statusID))
|
||||||
|
.flatMap { contentDatabase.insert(context: $0, parentID: statusID) })
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,8 +177,8 @@ public extension IdentityService {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func service(timeline: Timeline) -> StatusListService {
|
func service(timeline: Timeline) -> TimelineService {
|
||||||
StatusListService(timeline: timeline, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
TimelineService(timeline: timeline, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public extension NavigationService {
|
||||||
if let tag = tag(url: url) {
|
if let tag = tag(url: url) {
|
||||||
return Just(
|
return Just(
|
||||||
.collection(
|
.collection(
|
||||||
StatusListService(
|
TimelineService(
|
||||||
timeline: .tag(tag),
|
timeline: .tag(tag),
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
contentDatabase: contentDatabase)))
|
contentDatabase: contentDatabase)))
|
||||||
|
@ -39,13 +39,7 @@ public extension NavigationService {
|
||||||
} else if let accountID = accountID(url: url) {
|
} else if let accountID = accountID(url: url) {
|
||||||
return Just(.profile(profileService(id: accountID))).eraseToAnyPublisher()
|
return Just(.profile(profileService(id: accountID))).eraseToAnyPublisher()
|
||||||
} else if mastodonAPIClient.instanceURL.host == url.host, let statusID = url.statusID {
|
} else if mastodonAPIClient.instanceURL.host == url.host, let statusID = url.statusID {
|
||||||
return Just(
|
return Just(.collection(contextService(id: statusID))).eraseToAnyPublisher()
|
||||||
.collection(
|
|
||||||
StatusListService(
|
|
||||||
statusID: statusID,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase)))
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if url.shouldWebfinger {
|
if url.shouldWebfinger {
|
||||||
|
@ -55,8 +49,8 @@ public extension NavigationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func contextStatusListService(id: String) -> StatusListService {
|
func contextService(id: String) -> ContextService {
|
||||||
StatusListService(statusID: id, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
ContextService(statusID: id, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func profileService(id: String) -> ProfileService {
|
func profileService(id: String) -> ProfileService {
|
||||||
|
@ -113,18 +107,14 @@ private extension NavigationService {
|
||||||
.map { results -> Navigation in
|
.map { results -> Navigation in
|
||||||
if let tag = results.hashtags.first {
|
if let tag = results.hashtags.first {
|
||||||
return .collection(
|
return .collection(
|
||||||
StatusListService(
|
TimelineService(
|
||||||
timeline: .tag(tag.name),
|
timeline: .tag(tag.name),
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
contentDatabase: contentDatabase))
|
contentDatabase: contentDatabase))
|
||||||
} else if let account = results.accounts.first {
|
} else if let account = results.accounts.first {
|
||||||
return .profile(profileService(account: account))
|
return .profile(profileService(account: account))
|
||||||
} else if let status = results.statuses.first {
|
} else if let status = results.statuses.first {
|
||||||
return .collection(
|
return .collection(contextService(id: status.id))
|
||||||
StatusListService(
|
|
||||||
statusID: status.id,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase))
|
|
||||||
} else {
|
} else {
|
||||||
return .url(url)
|
return .url(url)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ public struct ProfileService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension ProfileService {
|
public extension ProfileService {
|
||||||
func statusListService(profileCollection: ProfileCollection) -> StatusListService {
|
func timelineService(profileCollection: ProfileCollection) -> TimelineService {
|
||||||
StatusListService(
|
TimelineService(
|
||||||
timeline: .profile(accountId: accountID, profileCollection: profileCollection),
|
timeline: .profile(accountId: accountID, profileCollection: profileCollection),
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
contentDatabase: contentDatabase)
|
contentDatabase: contentDatabase)
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import DB
|
|
||||||
import Foundation
|
|
||||||
import Mastodon
|
|
||||||
import MastodonAPI
|
|
||||||
|
|
||||||
public struct StatusListService: CollectionService {
|
|
||||||
public let sections: AnyPublisher<[[CollectionItem]], Error>
|
|
||||||
public let nextPageMaxIDs: AnyPublisher<String?, Never>
|
|
||||||
public let contextParentID: String?
|
|
||||||
public let title: String?
|
|
||||||
public let navigationService: NavigationService
|
|
||||||
|
|
||||||
private let filterContext: Filter.Context
|
|
||||||
private let mastodonAPIClient: MastodonAPIClient
|
|
||||||
private let contentDatabase: ContentDatabase
|
|
||||||
private let requestClosure: (_ maxID: String?, _ minID: String?) -> AnyPublisher<Never, Error>
|
|
||||||
}
|
|
||||||
|
|
||||||
extension StatusListService {
|
|
||||||
init(timeline: Timeline, mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) {
|
|
||||||
var title: String?
|
|
||||||
|
|
||||||
if case let .tag(tag) = timeline {
|
|
||||||
title = "#".appending(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
let nextPageMaxIDsSubject = PassthroughSubject<String?, Never>()
|
|
||||||
|
|
||||||
self.init(sections: contentDatabase.observation(timeline: timeline),
|
|
||||||
nextPageMaxIDs: nextPageMaxIDsSubject.eraseToAnyPublisher(),
|
|
||||||
contextParentID: nil,
|
|
||||||
title: title,
|
|
||||||
navigationService: NavigationService(
|
|
||||||
status: nil,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase),
|
|
||||||
filterContext: timeline.filterContext,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase) { maxID, minID in
|
|
||||||
mastodonAPIClient.pagedRequest(timeline.endpoint, maxID: maxID, minID: minID)
|
|
||||||
.handleEvents(receiveOutput: { nextPageMaxIDsSubject.send($0.info.maxID) })
|
|
||||||
.flatMap { contentDatabase.insert(statuses: $0.result, timeline: timeline) }
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(statusID: String, mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) {
|
|
||||||
self.init(sections: contentDatabase.contextObservation(parentID: statusID),
|
|
||||||
nextPageMaxIDs: Empty().eraseToAnyPublisher(),
|
|
||||||
contextParentID: statusID,
|
|
||||||
title: nil,
|
|
||||||
navigationService: NavigationService(
|
|
||||||
status: nil,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase),
|
|
||||||
filterContext: .thread,
|
|
||||||
mastodonAPIClient: mastodonAPIClient,
|
|
||||||
contentDatabase: contentDatabase) { _, _ in
|
|
||||||
Publishers.Merge(
|
|
||||||
mastodonAPIClient.request(StatusEndpoint.status(id: statusID))
|
|
||||||
.flatMap(contentDatabase.insert(status:))
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
mastodonAPIClient.request(ContextEndpoint.context(id: statusID))
|
|
||||||
.flatMap { contentDatabase.insert(context: $0, parentID: statusID) }
|
|
||||||
.eraseToAnyPublisher())
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension StatusListService {
|
|
||||||
func request(maxID: String?, minID: String?) -> AnyPublisher<Never, Error> {
|
|
||||||
requestClosure(maxID, minID)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import DB
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
import MastodonAPI
|
||||||
|
|
||||||
|
public struct TimelineService: CollectionService {
|
||||||
|
public let sections: AnyPublisher<[[CollectionItem]], Error>
|
||||||
|
public let navigationService: NavigationService
|
||||||
|
public let nextPageMaxIDs: AnyPublisher<String?, Never>
|
||||||
|
public let title: String?
|
||||||
|
public let contextParentID: String? = nil
|
||||||
|
|
||||||
|
private let timeline: Timeline
|
||||||
|
private let mastodonAPIClient: MastodonAPIClient
|
||||||
|
private let contentDatabase: ContentDatabase
|
||||||
|
private let nextPageMaxIDsSubject = PassthroughSubject<String?, Never>()
|
||||||
|
|
||||||
|
init(timeline: Timeline, mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) {
|
||||||
|
self.timeline = timeline
|
||||||
|
self.mastodonAPIClient = mastodonAPIClient
|
||||||
|
self.contentDatabase = contentDatabase
|
||||||
|
sections = contentDatabase.observation(timeline: timeline)
|
||||||
|
navigationService = NavigationService(
|
||||||
|
status: nil,
|
||||||
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
|
contentDatabase: contentDatabase)
|
||||||
|
nextPageMaxIDs = nextPageMaxIDsSubject.eraseToAnyPublisher()
|
||||||
|
|
||||||
|
if case let .tag(tag) = timeline {
|
||||||
|
title = "#".appending(tag)
|
||||||
|
} else {
|
||||||
|
title = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func request(maxID: String?, minID: String?) -> AnyPublisher<Never, Error> {
|
||||||
|
mastodonAPIClient.pagedRequest(timeline.endpoint, maxID: maxID, minID: minID)
|
||||||
|
.handleEvents(receiveOutput: { nextPageMaxIDsSubject.send($0.info.maxID) })
|
||||||
|
.flatMap { contentDatabase.insert(statuses: $0.result, timeline: timeline) }
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,7 +66,7 @@ extension ListViewModel: CollectionViewModel {
|
||||||
ListViewModel(
|
ListViewModel(
|
||||||
collectionService: collectionService
|
collectionService: collectionService
|
||||||
.navigationService
|
.navigationService
|
||||||
.contextStatusListService(id: configuration.status.displayStatus.id))))
|
.contextService(id: configuration.status.displayStatus.id))))
|
||||||
case .loadMore:
|
case .loadMore:
|
||||||
loadMoreViewModel(item: identifier)?.loadMore()
|
loadMoreViewModel(item: identifier)?.loadMore()
|
||||||
case let .account(account):
|
case let .account(account):
|
||||||
|
|
|
@ -18,7 +18,7 @@ final public class ProfileViewModel {
|
||||||
self.profileService = profileService
|
self.profileService = profileService
|
||||||
|
|
||||||
collectionViewModel = CurrentValueSubject(
|
collectionViewModel = CurrentValueSubject(
|
||||||
ListViewModel(collectionService: profileService.statusListService(profileCollection: .statuses)))
|
ListViewModel(collectionService: profileService.timelineService(profileCollection: .statuses)))
|
||||||
|
|
||||||
profileService.accountServicePublisher
|
profileService.accountServicePublisher
|
||||||
.map(AccountViewModel.init(accountService:))
|
.map(AccountViewModel.init(accountService:))
|
||||||
|
@ -26,7 +26,7 @@ final public class ProfileViewModel {
|
||||||
.assign(to: &$accountViewModel)
|
.assign(to: &$accountViewModel)
|
||||||
|
|
||||||
$collection.dropFirst()
|
$collection.dropFirst()
|
||||||
.map(profileService.statusListService(profileCollection:))
|
.map(profileService.timelineService(profileCollection:))
|
||||||
.map(ListViewModel.init(collectionService:))
|
.map(ListViewModel.init(collectionService:))
|
||||||
.sink { [weak self] in
|
.sink { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
Loading…
Reference in New Issue