diff --git a/Shared/Networking/Mastodon API/Endpoints/StatusEndpoint.swift b/Shared/Networking/Mastodon API/Endpoints/StatusEndpoint.swift index 1c24887..6133beb 100644 --- a/Shared/Networking/Mastodon API/Endpoints/StatusEndpoint.swift +++ b/Shared/Networking/Mastodon API/Endpoints/StatusEndpoint.swift @@ -3,6 +3,7 @@ import Foundation enum StatusEndpoint { + case status(id: String) case favourite(id: String) case unfavourite(id: String) } @@ -16,6 +17,8 @@ extension StatusEndpoint: MastodonEndpoint { var pathComponentsInContext: [String] { switch self { + case let .status(id): + return [id] case let .favourite(id): return [id, "favourite"] case let .unfavourite(id): @@ -25,6 +28,8 @@ extension StatusEndpoint: MastodonEndpoint { var method: HTTPMethod { switch self { + case .status: + return .get case .favourite, .unfavourite: return .post } diff --git a/Shared/Services/Status List Services/ContextService.swift b/Shared/Services/Status List Services/ContextService.swift index 2533de6..3282864 100644 --- a/Shared/Services/Status List Services/ContextService.swift +++ b/Shared/Services/Status List Services/ContextService.swift @@ -6,7 +6,7 @@ import Combine struct ContextService { let statusSections: AnyPublisher<[[Status]], Error> - private var status: Status + private let status: Status private let context = CurrentValueSubject(MastodonContext(ancestors: [], descendants: [])) private let networkClient: MastodonClient private let contentDatabase: ContentDatabase @@ -32,7 +32,7 @@ struct ContextService { } extension ContextService: StatusListService { - var contextParent: Status? { status } + var contextParentID: String? { status.id } func isReplyInContext(status: Status) -> Bool { let flatContext = flattenedContext() @@ -44,7 +44,7 @@ extension ContextService: StatusListService { let previousStatus = flatContext[index - 1] - return previousStatus.id != contextParent?.id && status.inReplyToId == previousStatus.id + return previousStatus.id != contextParentID && status.inReplyToId == previousStatus.id } func hasReplyFollowing(status: Status) -> Bool { @@ -57,14 +57,18 @@ extension ContextService: StatusListService { let nextStatus = flatContext[index + 1] - return status.id != contextParent?.id && nextStatus.inReplyToId == status.id + return status.id != contextParentID && nextStatus.inReplyToId == status.id } func request(maxID: String?, minID: String?) -> AnyPublisher { - networkClient.request(ContextEndpoint.context(id: status.id)) - .handleEvents(receiveOutput: context.send) - .map { ($0.ancestors + $0.descendants, collection) } - .flatMap(contentDatabase.insert(statuses:collection:)) + Publishers.Merge( + networkClient.request(StatusEndpoint.status(id: status.id)) + .map { ([$0], collection) } + .flatMap(contentDatabase.insert(statuses:collection:)), + networkClient.request(ContextEndpoint.context(id: status.id)) + .handleEvents(receiveOutput: context.send) + .map { ($0.ancestors + $0.descendants, collection) } + .flatMap(contentDatabase.insert(statuses:collection:))) .eraseToAnyPublisher() } diff --git a/Shared/Services/Status List Services/StatusListService.swift b/Shared/Services/Status List Services/StatusListService.swift index 5d26a4b..dccb8e0 100644 --- a/Shared/Services/Status List Services/StatusListService.swift +++ b/Shared/Services/Status List Services/StatusListService.swift @@ -5,7 +5,7 @@ import Combine protocol StatusListService { var statusSections: AnyPublisher<[[Status]], Error> { get } - var contextParent: Status? { get } + var contextParentID: String? { get } func isPinned(status: Status) -> Bool func isReplyInContext(status: Status) -> Bool func hasReplyFollowing(status: Status) -> Bool @@ -15,7 +15,7 @@ protocol StatusListService { } extension StatusListService { - var contextParent: Status? { nil } + var contextParentID: String? { nil } func isPinned(status: Status) -> Bool { false } diff --git a/Shared/View Models/StatusesViewModel.swift b/Shared/View Models/StatusesViewModel.swift index 111acb0..83074c6 100644 --- a/Shared/View Models/StatusesViewModel.swift +++ b/Shared/View Models/StatusesViewModel.swift @@ -26,7 +26,7 @@ class StatusesViewModel: ObservableObject { } extension StatusesViewModel { - var contextParent: Status? { statusListService.contextParent } + var contextParentID: String? { statusListService.contextParentID } func request(maxID: String? = nil, minID: String? = nil) { statusListService.request(maxID: maxID, minID: minID) @@ -51,7 +51,7 @@ extension StatusesViewModel { .sink {}) } - statusViewModel.isContextParent = status == contextParent + statusViewModel.isContextParent = status.id == contextParentID statusViewModel.isPinned = statusListService.isPinned(status: status) statusViewModel.isReplyInContext = statusListService.isReplyInContext(status: status) statusViewModel.hasReplyFollowing = statusListService.hasReplyFollowing(status: status) @@ -69,8 +69,8 @@ private extension StatusesViewModel { maintainScrollPositionOfStatusID = nil // clear old value // Maintain scroll position of parent after initial load of context - if let contextParent = contextParent, statusSections == [[], [contextParent], []] { - maintainScrollPositionOfStatusID = contextParent.id + if let contextParentID = contextParentID, statusSections.reduce([], +).map(\.id) == [contextParentID] { + maintainScrollPositionOfStatusID = contextParentID } } diff --git a/iOS/View Controllers/StatusListViewController.swift b/iOS/View Controllers/StatusListViewController.swift index 20eebf0..486b72f 100644 --- a/iOS/View Controllers/StatusListViewController.swift +++ b/iOS/View Controllers/StatusListViewController.swift @@ -101,7 +101,7 @@ class StatusListViewController: UITableViewController { } override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - viewModel.statusSections[indexPath.section][indexPath.row] != viewModel.contextParent + viewModel.statusSections[indexPath.section][indexPath.row].id != viewModel.contextParentID } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -123,11 +123,17 @@ extension StatusListViewController: StatusTableViewCellDelegate { private extension StatusListViewController { func indexPath(statusID: String) -> IndexPath? { - guard let status = viewModel.statusSections.reduce([], +).first(where: { $0.id == statusID }) else { - return nil + for section in 0..