Fix loading of home timeline (IOS-176)

This commit is contained in:
Marcus Kida 2023-11-22 13:18:41 +01:00
parent b010b6112e
commit 9ce078ce3e
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
6 changed files with 58 additions and 28 deletions

View File

@ -21,7 +21,6 @@ extension HomeTimelineViewController: DataSourceProvider {
switch item {
case .feed(let feed):
let managedObjectContext = context.managedObjectContext
let item: DataSourceItem? = {
guard feed.kind == .home else { return nil }
if let status = feed.status {

View File

@ -80,7 +80,7 @@ final class HomeTimelineViewModel: NSObject {
init(context: AppContext, authContext: AuthContext) {
self.context = context
self.authContext = authContext
self.fetchedResultsController = FeedFetchedResultsController()
self.fetchedResultsController = FeedFetchedResultsController(context: context, authContext: authContext)
self.homeTimelineNavigationBarTitleViewModel = HomeTimelineNavigationBarTitleViewModel(context: context)
super.init()
homeTimelineNeedRefresh
@ -97,6 +97,8 @@ final class HomeTimelineViewModel: NSObject {
self.homeTimelineNeedRefresh.send()
}
.store(in: &disposeBag)
self.fetchedResultsController.loadInitial(kind: .home)
}
}
@ -110,7 +112,7 @@ extension HomeTimelineViewModel {
extension HomeTimelineViewModel {
func timelineDidReachEnd() {
#warning("Check if required, e.g. when locally caching MastodonStatus")
fetchedResultsController.loadNext(kind: .home)
}
}
@ -122,29 +124,9 @@ extension HomeTimelineViewModel {
guard let diffableDataSource = diffableDataSource else { return }
var snapshot = diffableDataSource.snapshot()
// let managedObjectContext = context.managedObjectContext
// let key = "LoadMore@\(record.objectID)"
//
// guard let feed = record.object(in: managedObjectContext) else { return }
guard let status = record.status else { return }
record.isLoadingMore = true
// // keep transient property live
// managedObjectContext.cache(feed, key: key)
// defer {
// managedObjectContext.cache(nil, key: key)
// }
// do {
// // update state
// try await managedObjectContext.performChanges {
// feed.update(isLoadingMore: true)
// }
// } catch {
// assertionFailure(error.localizedDescription)
// }
// reconfigure item
snapshot.reconfigureItems([item])
await updateSnapshotUsingReloadData(snapshot: snapshot)

View File

@ -52,7 +52,7 @@ final class NotificationTimelineViewModel {
self.context = context
self.authContext = authContext
self.scope = scope
self.feedFetchedResultsController = FeedFetchedResultsController()
self.feedFetchedResultsController = FeedFetchedResultsController(context: context, authContext: authContext)
}

View File

@ -14,6 +14,44 @@ import MastodonSDK
final public class FeedFetchedResultsController {
@Published public var records: [MastodonFeed] = []
private let context: AppContext
private let authContext: AuthContext
public init() {}
public init(context: AppContext, authContext: AuthContext) {
self.context = context
self.authContext = authContext
}
public func loadInitial(kind: MastodonFeed.Kind) {
Task {
records = try await load(kind: kind, sinceId: nil)
}
}
public func loadNext(kind: MastodonFeed.Kind) {
Task {
guard let lastId = records.last?.status?.id else {
return loadInitial(kind: kind)
}
records = try await load(kind: kind, sinceId: lastId)
}
}
}
private extension FeedFetchedResultsController {
func load(kind: MastodonFeed.Kind, sinceId: MastodonStatus.ID?) async throws -> [MastodonFeed] {
switch kind {
case .home:
return try await context.apiService.homeTimeline(sinceID: sinceId, authenticationBox: authContext.mastodonAuthenticationBox)
.value.map { .fromStatus(.fromEntity($0), kind: .home) }
case .notificationAll:
return try await context.apiService.notifications(maxID: nil, scope: .everything, authenticationBox: authContext.mastodonAuthenticationBox)
.value.map { .fromNotification($0, kind: .notificationAll) }
case .notificationMentions:
return try await context.apiService.notifications(maxID: nil, scope: .mentions, authenticationBox: authContext.mastodonAuthenticationBox)
.value.map { .fromNotification($0, kind: .notificationMentions) }
}
}
}

View File

@ -13,7 +13,8 @@ import MastodonSDK
public final class StatusFetchedResultsController {
@MainActor
@Published public private(set) var records: [MastodonStatus] = []
@Published
public private(set) var records: [MastodonStatus] = []
@MainActor
public init(records: [MastodonStatus] = []) {

View File

@ -4,6 +4,14 @@ import Foundation
import CoreDataStack
public final class MastodonFeed {
public enum Kind {
case home
case notificationAll
case notificationMentions
}
public let id: String
public var hasMore: Bool = false
public var isLoadingMore: Bool = false
@ -13,6 +21,7 @@ public final class MastodonFeed {
public let kind: Feed.Kind
init(hasMore: Bool, isLoadingMore: Bool, status: MastodonStatus?, notification: Mastodon.Entity.Notification?, kind: Feed.Kind) {
self.id = status?.id ?? notification?.id ?? UUID().uuidString
self.hasMore = hasMore
self.isLoadingMore = isLoadingMore
self.status = status
@ -45,10 +54,11 @@ public extension MastodonFeed {
extension MastodonFeed: Hashable {
public static func == (lhs: MastodonFeed, rhs: MastodonFeed) -> Bool {
lhs.status?.id == rhs.status?.id || lhs.notification?.id == rhs.notification?.id
lhs.id == rhs.id && (lhs.status?.id == rhs.status?.id || lhs.notification?.id == rhs.notification?.id)
}
public func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(status)
hasher.combine(notification)
}