// Copyright © 2020 Metabolist. All rights reserved. import Combine import DB import Foundation import Mastodon import MastodonAPI public struct TimelineService { public let sections: AnyPublisher<[CollectionSection], Error> public let navigationService: NavigationService public let nextPageMaxId: AnyPublisher public let accountIdsForRelationships: AnyPublisher, Never> public let title: AnyPublisher public let titleLocalizationComponents: AnyPublisher<[String], Never> public let announcesNewItems = true private let timeline: Timeline private let mastodonAPIClient: MastodonAPIClient private let contentDatabase: ContentDatabase private let nextPageMaxIdSubject = PassthroughSubject() private let accountIdsForRelationshipsSubject = PassthroughSubject, Never>() init(timeline: Timeline, environment: AppEnvironment, mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) { self.timeline = timeline self.mastodonAPIClient = mastodonAPIClient self.contentDatabase = contentDatabase if case .home = timeline { sections = contentDatabase.cleanHomeTimelinePublisher() .collect() .flatMap { _ in contentDatabase.timelinePublisher(timeline) } .eraseToAnyPublisher() } else { sections = contentDatabase.timelinePublisher(timeline) } navigationService = NavigationService(environment: environment, mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase) nextPageMaxId = nextPageMaxIdSubject.eraseToAnyPublisher() accountIdsForRelationships = accountIdsForRelationshipsSubject.eraseToAnyPublisher() switch timeline { case let .list(list): title = Just(list.title).eraseToAnyPublisher() titleLocalizationComponents = Empty().eraseToAnyPublisher() case let .tag(tag): title = Just("#".appending(tag)).eraseToAnyPublisher() titleLocalizationComponents = Empty().eraseToAnyPublisher() case .favorites: title = Empty().eraseToAnyPublisher() titleLocalizationComponents = Just(["favorites"]).eraseToAnyPublisher() case .bookmarks: title = Empty().eraseToAnyPublisher() titleLocalizationComponents = Just(["bookmarks"]).eraseToAnyPublisher() default: title = Empty().eraseToAnyPublisher() titleLocalizationComponents = Empty().eraseToAnyPublisher() } } } extension TimelineService: CollectionService { public var positionTimeline: Timeline? { timeline } public var preferLastPresentIdOverNextPageMaxId: Bool { !timeline.ordered } public func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher { mastodonAPIClient.pagedRequest(timeline.endpoint, maxId: maxId, minId: minId) .handleEvents(receiveOutput: { if let maxId = $0.info.maxId { nextPageMaxIdSubject.send(maxId) } accountIdsForRelationshipsSubject.send( Set($0.result.map(\.account.id)) .union(Set($0.result.compactMap(\.reblog?.account.id)))) }) .flatMap { contentDatabase.insert(statuses: $0.result, timeline: timeline) } .eraseToAnyPublisher() } }