From a3491cec852d98ea38dfb5ec796744382dcccf69 Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Sat, 23 Jan 2021 23:21:35 -0800 Subject: [PATCH] Fix interacgtion with statuses in search results --- DB/Sources/DB/Content/ContentDatabase.swift | 76 +++++++++++++------ .../ServiceLayer/Services/SearchService.swift | 9 +-- Views/LineChartView.swift | 6 +- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/DB/Sources/DB/Content/ContentDatabase.swift b/DB/Sources/DB/Content/ContentDatabase.swift index 2e2c883..9e6381b 100644 --- a/DB/Sources/DB/Content/ContentDatabase.swift +++ b/DB/Sources/DB/Content/ContentDatabase.swift @@ -425,37 +425,17 @@ public extension ContentDatabase { .eraseToAnyPublisher() } - func process(results: Results) -> AnyPublisher<[CollectionSection], Error> { - databaseWriter.writePublisher { db -> ([StatusInfo], [Status.Id]) in + func insert(results: Results) -> AnyPublisher { + databaseWriter.writePublisher { for account in results.accounts { - try account.save(db) + try account.save($0) } for status in results.statuses { - try status.save(db) + try status.save($0) } - - let ids = results.statuses.map(\.id) - let statusInfos = try StatusInfo.request( - StatusRecord.filter(ids.contains(StatusRecord.Columns.id))) - .fetchAll(db) - - return (statusInfos, ids) - } - .map { statusInfos, ids -> [CollectionSection] in - [ - .init(items: results.accounts.map(CollectionItem.account), titleLocalizedStringKey: "search.accounts"), - .init(items: statusInfos - .sorted { ids.firstIndex(of: $0.record.id) ?? 0 < ids.firstIndex(of: $1.record.id) ?? 0 } - .map { - .status(.init(info: $0), - .init(showContentToggled: $0.showContentToggled, - showAttachmentsToggled: $0.showAttachmentsToggled)) - }, - titleLocalizedStringKey: "search.statuses"), - .init(items: results.hashtags.map(CollectionItem.tag), titleLocalizedStringKey: "search.tags") - ] } + .ignoreOutput() .eraseToAnyPublisher() } @@ -528,6 +508,52 @@ public extension ContentDatabase { .eraseToAnyPublisher() } + func publisher(results: Results) -> AnyPublisher<[CollectionSection], Error> { + let accountIds = results.accounts.map(\.id) + let statusIds = results.statuses.map(\.id) + + let accountsPublisher = ValueObservation.tracking( + AccountInfo.request( + AccountRecord.filter(accountIds.contains(AccountRecord.Columns.id))) + .fetchAll) + .removeDuplicates() + .publisher(in: databaseWriter) + .map { + $0.sorted { + accountIds.firstIndex(of: $0.record.id) ?? 0 + < accountIds.firstIndex(of: $1.record.id) ?? 0 + } + .map { CollectionItem.account(.init(info: $0)) } + } + + let statusesPublisher = ValueObservation.tracking( + StatusInfo.request( + StatusRecord.filter(statusIds.contains(StatusRecord.Columns.id))) + .fetchAll) + .removeDuplicates() + .publisher(in: databaseWriter) + .map { + $0.sorted { + statusIds.firstIndex(of: $0.record.id) ?? 0 + < statusIds.firstIndex(of: $1.record.id) ?? 0 + } + .map { + CollectionItem.status( + .init(info: $0), + .init(showContentToggled: $0.showContentToggled, + showAttachmentsToggled: $0.showAttachmentsToggled)) + } + } + + return accountsPublisher.combineLatest(statusesPublisher) + .map { accounts, statuses in + [.init(items: accounts, titleLocalizedStringKey: "search.accounts"), + .init(items: statuses, titleLocalizedStringKey: "search.statuses"), + .init(items: results.hashtags.map(CollectionItem.tag), titleLocalizedStringKey: "search.tags")] + } + .eraseToAnyPublisher() + } + func notificationsPublisher() -> AnyPublisher<[CollectionSection], Error> { ValueObservation.tracking( NotificationInfo.request( diff --git a/ServiceLayer/Sources/ServiceLayer/Services/SearchService.swift b/ServiceLayer/Sources/ServiceLayer/Services/SearchService.swift index 08277fc..5c81175 100644 --- a/ServiceLayer/Sources/ServiceLayer/Services/SearchService.swift +++ b/ServiceLayer/Sources/ServiceLayer/Services/SearchService.swift @@ -14,14 +14,14 @@ public struct SearchService { private let mastodonAPIClient: MastodonAPIClient private let contentDatabase: ContentDatabase private let nextPageMaxIdSubject = PassthroughSubject() - private let sectionsSubject = PassthroughSubject<[CollectionSection], Error>() + private let resultsSubject = PassthroughSubject() init(mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) { self.mastodonAPIClient = mastodonAPIClient self.contentDatabase = contentDatabase nextPageMaxId = nextPageMaxIdSubject.eraseToAnyPublisher() navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase) - sections = sectionsSubject.eraseToAnyPublisher() + sections = resultsSubject.flatMap(contentDatabase.publisher(results:)).eraseToAnyPublisher() } } @@ -30,9 +30,8 @@ extension SearchService: CollectionService { guard let search = search else { return Empty().eraseToAnyPublisher() } return mastodonAPIClient.request(ResultsEndpoint.search(search)) - .flatMap(contentDatabase.process(results:)) - .handleEvents(receiveOutput: sectionsSubject.send) - .ignoreOutput() + .handleEvents(receiveOutput: resultsSubject.send) + .flatMap(contentDatabase.insert(results:)) .eraseToAnyPublisher() } } diff --git a/Views/LineChartView.swift b/Views/LineChartView.swift index b60cc90..2f96385 100644 --- a/Views/LineChartView.swift +++ b/Views/LineChartView.swift @@ -31,12 +31,14 @@ final class LineChartView: UIView { guard valueCount > 0, let maxValue = values.max() else { return } + let inset = Self.lineWidth / 2 + for (index, value) in values.enumerated() { let x = CGFloat(index) / CGFloat(valueCount) * rect.width let y = rect.height - CGFloat(value) / max(CGFloat(maxValue), CGFloat(0).nextUp) * rect.height let point = CGPoint( - x: min(max(x, Self.lineWidth / 2), rect.width - Self.lineWidth / 2), - y: min(max(y, Self.lineWidth / 2), rect.height - Self.lineWidth / 2)) + x: min(max(x, inset), rect.width - inset), + y: min(max(y, inset), rect.height - inset)) if index > 0 { path.addLine(to: point)