Merge pull request #111 from omnivore-app/feature/incremental-library-loading

Incremental Home Feed Loading [Apple]
This commit is contained in:
Satindar Dhillon
2022-02-23 08:22:47 -08:00
committed by GitHub
5 changed files with 24 additions and 15 deletions

View File

@ -12,15 +12,17 @@ extension HomeFeedViewModel {
}
viewModel.bind(services: services)
viewModel.loadItems(dataService: services.dataService, searchQuery: nil)
viewModel.loadItems(dataService: services.dataService, searchQuery: nil, isRefresh: false)
return viewModel
}
func bind(services: Services) {
performActionSubject.sink { [weak self] action in
switch action {
case let .refreshItems(query: query):
self?.loadItems(dataService: services.dataService, searchQuery: query, isRefresh: true)
case let .loadItems(query):
self?.loadItems(dataService: services.dataService, searchQuery: query)
self?.loadItems(dataService: services.dataService, searchQuery: query, isRefresh: false)
case let .archive(linkId):
self?.setLinkArchived(dataService: services.dataService, linkId: linkId, archived: true)
case let .unarchive(linkId):
@ -39,7 +41,7 @@ extension HomeFeedViewModel {
.store(in: &subscriptions)
}
private func loadItems(dataService: DataService, searchQuery: String?) {
private func loadItems(dataService: DataService, searchQuery: String?, isRefresh: Bool) {
// Clear offline highlights since we'll be populating new FeedItems with the correct highlights set
dataService.clearHighlights()
@ -59,10 +61,10 @@ extension HomeFeedViewModel {
}
dataService.libraryItemsPublisher(
limit: 100,
limit: 10,
sortDescending: true,
searchQuery: searchQuery,
cursor: nil
cursor: isRefresh ? nil : cursor
)
.sink(
receiveCompletion: { [weak self] completion in
@ -80,9 +82,10 @@ extension HomeFeedViewModel {
if thisSearchIdx > 0, thisSearchIdx <= self?.receivedIdx ?? 0 {
return
}
self?.items = result.items
self?.items = isRefresh ? result.items : (self?.items ?? []) + result.items
self?.isLoading = false
self?.receivedIdx = thisSearchIdx
self?.cursor = result.cursor
stopNetworkActivityIndicator()
}
)

View File

@ -2,9 +2,11 @@ import Foundation
public struct HomeFeedData {
public let items: [FeedItem]
public let cursor: String?
public init(items: [FeedItem]) {
public init(items: [FeedItem], cursor: String?) {
self.items = items
self.cursor = cursor
}
}

View File

@ -71,7 +71,10 @@ public extension DataService {
articlesSuccess: .init {
QueryResult.success(
result: HomeFeedData(
items: try $0.edges(selection: articleEdgeSelection.list)
items: try $0.edges(selection: articleEdgeSelection.list),
cursor: try $0.pageInfo(selection: Selection.PageInfo {
try $0.endCursor()
})
)
)
},

View File

@ -10,6 +10,7 @@ public final class HomeFeedViewModel: ObservableObject {
@Published public var items = [FeedItem]()
@Published public var isLoading = false
@Published public var showPushNotificationPrimer = false
public var cursor: String?
// These are used to make sure we handle search result
// responses in the right order
@ -17,6 +18,7 @@ public final class HomeFeedViewModel: ObservableObject {
public var receivedIdx = 0
public enum Action {
case refreshItems(query: String)
case loadItems(query: String)
case archive(linkId: String)
case unarchive(linkId: String)
@ -31,15 +33,14 @@ public final class HomeFeedViewModel: ObservableObject {
self.detailViewModelCreator = detailViewModelCreator
}
func itemAppeared(item: FeedItem) {
func itemAppeared(item: FeedItem, searchQuery: String) {
if isLoading { return }
let itemIndex = items.firstIndex(where: { $0.id == item.id })
let thresholdIndex = items.index(items.endIndex, offsetBy: -5)
// Check if user has scrolled to the last five items in the list
if itemIndex == thresholdIndex {
print("load more items triggered")
// performActionSubject.send(.loadItems)
if let itemIndex = itemIndex, itemIndex > thresholdIndex, items.count < thresholdIndex + 10 {
performActionSubject.send(.loadItems(query: searchQuery))
}
}
@ -124,7 +125,7 @@ public struct HomeFeedView: View {
.opacity(0)
.buttonStyle(PlainButtonStyle())
.onAppear {
viewModel.itemAppeared(item: item)
viewModel.itemAppeared(item: item, searchQuery: searchQuery)
}
FeedCard(item: item)
}.contextMenu {
@ -268,6 +269,6 @@ public struct HomeFeedView: View {
}
private func refresh() {
viewModel.performActionSubject.send(.loadItems(query: searchQuery))
viewModel.performActionSubject.send(.refreshItems(query: searchQuery))
}
}

File diff suppressed because one or more lines are too long