Better separation of sync and search
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -73,7 +73,7 @@ public struct LibrarySplitView: View {
|
||||
}
|
||||
.onReceive(NSNotification.performSyncPublisher) { _ in
|
||||
Task {
|
||||
await syncManager.syncItems(dataService: dataService)
|
||||
await syncManager.syncUpdates(dataService: dataService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user