From 3362a5b0169ea0eadc72f22aca36edb8fa37bbcf Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 26 Dec 2023 14:23:39 +0800 Subject: [PATCH] Better separation of sync and search --- .../Home/Components/LibraryItemFetcher.swift | 25 +++++++++++++------ .../App/Views/Home/HomeFeedViewIOS.swift | 4 +-- .../Sources/App/Views/LibrarySplitView.swift | 2 +- .../Sources/App/Views/LibraryTabView.swift | 2 +- .../Sources/Models/DataModels/FeedItem.swift | 10 +++++++- .../Public/LinkedItemLoading.swift | 15 +++++++---- .../Queries/LinkedItemNetworkQuery.swift | 12 +++++---- 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/LibraryItemFetcher.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/LibraryItemFetcher.swift index bf6abc29b..ebe59074c 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/LibraryItemFetcher.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/LibraryItemFetcher.swift @@ -16,6 +16,7 @@ import Views @AppStorage(UserDefaultKey.lastSelectedFeaturedItemFilter.rawValue) var featureFilter = FeaturedItemFilter.continueReading.rawValue + var limit = 10 var cursor: String? var totalCount: Int? @@ -55,11 +56,17 @@ import Views return } - let queryResult = try? await dataService.loadLinkedItems( - limit: 10, - searchQuery: searchQuery(filterState), - cursor: isRefresh ? nil : loadCursor ?? cursor - ) + var queryResult: LinkedItemQueryResult? + + do { + queryResult = try await dataService.loadLinkedItems( + limit: limit, + searchQuery: searchQuery(filterState), + cursor: isRefresh ? nil : loadCursor ?? cursor + ) + } catch { + print("ERROR loading library items: ", error) + } if let appliedFilter = filterState.appliedFilter, let queryResult = queryResult { let newItems: [Models.LibraryItem] = { @@ -70,6 +77,9 @@ import Views return itemObjects }() + print("LOAD CURSOR: ", loadCursor, " new cursor: ", queryResult.cursor) + print("NEW ITEMS: ", newItems.count, newItems.map { "\($0.title)\n" }) + if filterState.searchTerm.replacingOccurrences(of: " ", with: "").isEmpty, appliedFilter.allowLocalFetch { updateFetchController(dataService: dataService, filterState: filterState) } else { @@ -82,6 +92,8 @@ import Views } receivedIdx = thisSearchIdx + + limit = 20 // Once we have one successful fetch with 10 items we increase to 20 per fetch cursor = queryResult.cursor totalCount = queryResult.totalCount @@ -117,7 +129,7 @@ import Views func loadMoreItems(dataService: DataService, filterState: FetcherFilterState, loadCursor: String? = nil) async { if let appliedFilter = filterState.appliedFilter, appliedFilter.shouldRemoteSearch { - let idx = max(items.count - 1, 0) + let idx = max(items.count, 0) await loadSearchQuery( dataService: dataService, filterState: filterState, @@ -187,7 +199,6 @@ import Views sectionNameKeyPath: nil, cacheName: nil ) - guard let fetchedResultsController = fetchedResultsController else { return } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index a140dcf9a..1a9de798a 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -683,7 +683,7 @@ struct AnimatingCellHeight: AnimatableModifier { .onAppear { if idx >= viewModel.fetcher.items.count - 5 { Task { - await viewModel.loadMore(dataService: dataService, loadCursor: idx.description) + await viewModel.loadMore(dataService: dataService) } } } @@ -1031,7 +1031,7 @@ struct BottomView: View { } var innerBody: some View { - if viewModel.fetcher.items.count < 5 { + if viewModel.fetcher.items.count < 3 { AnyView(Color.clear) } else { AnyView(HStack { diff --git a/apple/OmnivoreKit/Sources/App/Views/LibrarySplitView.swift b/apple/OmnivoreKit/Sources/App/Views/LibrarySplitView.swift index c7f0b144a..a60d4274a 100644 --- a/apple/OmnivoreKit/Sources/App/Views/LibrarySplitView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/LibrarySplitView.swift @@ -73,7 +73,7 @@ public struct LibrarySplitView: View { } .onReceive(NSNotification.performSyncPublisher) { _ in Task { - await syncManager.syncItems(dataService: dataService) + await syncManager.syncUpdates(dataService: dataService) } } } diff --git a/apple/OmnivoreKit/Sources/App/Views/LibraryTabView.swift b/apple/OmnivoreKit/Sources/App/Views/LibraryTabView.swift index 4baad2b2f..a307922c0 100644 --- a/apple/OmnivoreKit/Sources/App/Views/LibraryTabView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/LibraryTabView.swift @@ -123,7 +123,7 @@ struct LibraryTabView: View { .navigationBarHidden(true) .onReceive(NSNotification.performSyncPublisher) { _ in Task { - await syncManager.syncItems(dataService: dataService) + await syncManager.syncUpdates(dataService: dataService) } } .onOpenURL { url in diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index 97892c561..70e016241 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -19,13 +19,21 @@ public struct LinkedItemSyncResult { public let cursor: String? public let hasMore: Bool public let mostRecentUpdatedAt: Date? + public let oldestUpdatedAt: Date? public let isEmpty: Bool - public init(updatedItemIDs: [String], cursor: String?, hasMore: Bool, mostRecentUpdatedAt: Date?, isEmpty: Bool) { + public init(updatedItemIDs: [String], + cursor: String?, + hasMore: Bool, + mostRecentUpdatedAt: Date?, + oldestUpdatedAt: Date?, + isEmpty: Bool) + { self.updatedItemIDs = updatedItemIDs self.cursor = cursor self.hasMore = hasMore self.mostRecentUpdatedAt = mostRecentUpdatedAt + self.oldestUpdatedAt = oldestUpdatedAt self.isEmpty = isEmpty } } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Public/LinkedItemLoading.swift b/apple/OmnivoreKit/Sources/Services/DataService/Public/LinkedItemLoading.swift index e9d1028da..1ecfda57a 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Public/LinkedItemLoading.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Public/LinkedItemLoading.swift @@ -15,17 +15,22 @@ public extension DataService { LibraryItem.deleteItems(ids: fetchResult.deletedItemIDs, context: backgroundContext) - if fetchResult.items.persist(context: backgroundContext) == nil { - throw BasicError.message(messageText: "CoreData error") + if !fetchResult.updatedItems.isEmpty { + if fetchResult.updatedItems.persist(context: backgroundContext) == nil { + throw BasicError.message(messageText: "CoreData error") + } } - let newestChange = fetchResult.items.max { $0.updatedAt < $1.updatedAt } + let newestChange = fetchResult.updatedItems.max { $0.updatedAt < $1.updatedAt } + let oldestChange = fetchResult.updatedItems.min { $0.updatedAt < $1.updatedAt } + let result = LinkedItemSyncResult( - updatedItemIDs: fetchResult.items.map(\.id), + updatedItemIDs: fetchResult.updatedItems.map(\.id), cursor: fetchResult.cursor, hasMore: fetchResult.hasMoreItems, mostRecentUpdatedAt: newestChange?.updatedAt, - isEmpty: fetchResult.deletedItemIDs.isEmpty && fetchResult.items.isEmpty + oldestUpdatedAt: oldestChange?.updatedAt, + isEmpty: fetchResult.deletedItemIDs.isEmpty && fetchResult.updatedItems.isEmpty ) return result diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/LinkedItemNetworkQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/LinkedItemNetworkQuery.swift index 3ad941930..1accb4ebd 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/LinkedItemNetworkQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/LinkedItemNetworkQuery.swift @@ -10,8 +10,8 @@ struct InternalLinkedItemQueryResult { } struct InternalLinkedItemUpdatesQueryResult { - let items: [InternalLibraryItem] let deletedItemIDs: [String] + let updatedItems: [InternalLibraryItem] let cursor: String? let hasMoreItems: Bool let totalCount: Int @@ -20,6 +20,7 @@ struct InternalLinkedItemUpdatesQueryResult { private struct SyncItemEdge { let itemID: String let isDeletedItem: Bool + let isUpdatedItem: Bool let item: InternalLibraryItem? } @@ -91,21 +92,21 @@ extension DataService { switch payload.data { case let .success(result: result): - var items = [InternalLibraryItem]() + var updatedItems = [InternalLibraryItem]() var deletedItemIDs = [String]() for edge in result.edges { if edge.isDeletedItem { deletedItemIDs.append(edge.itemID) - } else if let item = edge.item { - items.append(item) + } else if let item = edge.item, edge.isUpdatedItem { + updatedItems.append(item) } } continuation.resume( returning: InternalLinkedItemUpdatesQueryResult( - items: items, deletedItemIDs: deletedItemIDs, + updatedItems: updatedItems, cursor: result.cursor, hasMoreItems: result.hasMoreItems, totalCount: result.totalCount @@ -292,6 +293,7 @@ private let syncItemEdgeSelection = Selection.SyncUpdatedItemEdge { SyncItemEdge( itemID: try $0.itemId(), isDeletedItem: try $0.updateReason() == .deleted, + isUpdatedItem: try $0.updateReason() == .updated, item: try $0.node(selection: searchItemSelection.nullable) ) }