use search api to fill gaps sync might miss

This commit is contained in:
Satindar Dhillon
2023-02-28 12:37:16 -08:00
parent 0282dcb4ad
commit e66531cd77
4 changed files with 114 additions and 26 deletions

View File

@ -4,6 +4,39 @@ import android.util.Log
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.persistence.entities.*
suspend fun DataService.librarySearch(cursor: String?, query: String): SavedItemSyncResult {
val searchResult = networker.search(cursor = cursor, limit = 10, query = query)
val savedItems = searchResult.items.map { it.item }
db.savedItemDao().insertAll(savedItems)
val labels: MutableList<SavedItemLabel> = mutableListOf()
val crossRefs: MutableList<SavedItemAndSavedItemLabelCrossRef> = mutableListOf()
// save labels
for (searchItem in searchResult.items) {
labels.addAll(searchItem.labels)
val newCrossRefs = searchItem.labels.map {
SavedItemAndSavedItemLabelCrossRef(savedItemLabelId = it.savedItemLabelId, savedItemId = searchItem.item.savedItemId)
}
crossRefs.addAll(newCrossRefs)
}
db.savedItemLabelDao().insertAll(labels)
db.savedItemAndSavedItemLabelCrossRefDao().insertAll(crossRefs)
return SavedItemSyncResult(
hasError = false,
hasMoreItems = false,
cursor = searchResult.cursor,
count = searchResult.items.size,
savedItemSlugs = savedItems.map { it.slug }
)
}
suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): SavedItemSyncResult {
val syncResult = networker.savedItemUpdates(cursor = cursor, limit = limit, since = since) ?: return SavedItemSyncResult.errorResult

View File

@ -2,7 +2,9 @@ package app.omnivore.omnivore.networking
import app.omnivore.omnivore.graphql.generated.SearchQuery
import app.omnivore.omnivore.graphql.generated.TypeaheadSearchQuery
import app.omnivore.omnivore.persistence.entities.SavedItem
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
import com.apollographql.apollo3.api.Optional
data class SearchQueryResponse(
@ -10,6 +12,16 @@ data class SearchQueryResponse(
val cardsData: List<SavedItemCardData>
)
data class LibrarySearchQueryResponse(
val cursor: String?,
val items: List<LibrarySearchItem>
)
data class LibrarySearchItem(
val item: SavedItem,
val labels: List<SavedItemLabel>
)
suspend fun Networker.typeaheadSearch(
query: String
): SearchQueryResponse {
@ -44,7 +56,7 @@ suspend fun Networker.search(
cursor: String? = null,
limit: Int = 15,
query: String
): SearchQueryResponse {
): LibrarySearchQueryResponse {
try {
val result = authenticatedApolloClient().query(
SearchQuery(
@ -57,22 +69,46 @@ suspend fun Networker.search(
val newCursor = result.data?.search?.onSearchSuccess?.pageInfo?.endCursor
val itemList = result.data?.search?.onSearchSuccess?.edges ?: listOf()
val cardsData = itemList.map {
SavedItemCardData(
savedItemId = it.node.id,
slug = it.node.slug,
publisherURLString = it.node.originalArticleUrl,
title = it.node.title,
author = it.node.author,
imageURLString = it.node.image,
isArchived = it.node.isArchived,
pageURLString = it.node.url,
contentReader = it.node.contentReader.rawValue,
val searchItems = itemList.map {
LibrarySearchItem(
item = SavedItem(
savedItemId = it.node.id,
title = it.node.title,
createdAt = it.node.createdAt as String,
savedAt = it.node.savedAt as String,
readAt = it.node.readAt as String?,
updatedAt = it.node.updatedAt as String?,
readingProgress = it.node.readingProgressPercent,
readingProgressAnchor = it.node.readingProgressAnchorIndex,
imageURLString = it.node.image,
pageURLString = it.node.url,
descriptionText = it.node.description,
publisherURLString = it.node.originalArticleUrl,
siteName = it.node.siteName,
author = it.node.author,
publishDate = it.node.publishedAt as String?,
slug = it.node.slug,
isArchived = it.node.isArchived,
contentReader = it.node.contentReader.rawValue,
content = null
),
labels = (it.node.labels ?: listOf()).map { label ->
SavedItemLabel(
savedItemLabelId = label.id,
name = label.name,
color = label.color,
createdAt = null,
labelDescription = null
)
}
)
}
return SearchQueryResponse(newCursor, cardsData)
return LibrarySearchQueryResponse(
cursor = newCursor,
items = searchItems
)
} catch (e: java.lang.Exception) {
return SearchQueryResponse(null, listOf())
return LibrarySearchQueryResponse(null, listOf())
}
}

View File

@ -109,7 +109,11 @@ fun LibraryViewContent(libraryViewModel: LibraryViewModel, modifier: Modifier) {
}
InfiniteListHandler(listState = listState) {
libraryViewModel.load()
if (cardsData.isEmpty()) {
libraryViewModel.load()
} else {
libraryViewModel.loadUsingSearchAPI()
}
}
PullRefreshIndicator(

View File

@ -25,6 +25,7 @@ class LibraryViewModel @Inject constructor(
private val datastoreRepo: DatastoreRepository
): ViewModel() {
private var cursor: String? = null
private var librarySearchCursor: String? = null
// These are used to make sure we handle search result
// responses in the right order
@ -108,6 +109,21 @@ class LibraryViewModel @Inject constructor(
performSearch(clearPreviousSearch)
} else {
syncItems()
loadUsingSearchAPI()
}
}
}
fun loadUsingSearchAPI() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val result = dataService.librarySearch(cursor = librarySearchCursor, query = searchQueryString())
result.cursor?.let {
librarySearchCursor = it
}
CoroutineScope(Dispatchers.Main).launch {
isRefreshing = false
}
}
}
}
@ -136,6 +152,7 @@ class LibraryViewModel @Inject constructor(
}
suspend fun handleFilterChanges() {
librarySearchCursor = null
if (searchTextLiveData.value != "") {
performSearch(true)
} else if (appliedSortFilterLiveData.value != null && appliedFilterLiveData.value != null) {
@ -194,7 +211,7 @@ class LibraryViewModel @Inject constructor(
searchIdx += 1
// Execute the search
val searchResult = networker.typeaheadSearch(searchQueryString())
val searchResult = networker.typeaheadSearch(searchTextLiveData.value ?: "")
// Search results aren't guaranteed to return in order so this
// will discard old results that are returned while a user is typing.
@ -237,16 +254,14 @@ class LibraryViewModel @Inject constructor(
}
private fun searchQueryString(): String {
return searchTextLiveData.value ?: ""
// Unused code for typeahead search
// var query = "${appliedFilterLiveData.value?.queryString} ${appliedSortFilterLiveData.value?.queryString}"
// val searchText = searchTextLiveData.value ?: ""
//
// if (searchText.isNotEmpty()) {
// query += " $searchText"
// }
//
// return query
var query = "${appliedFilterLiveData.value?.queryString} ${appliedSortFilterLiveData.value?.queryString}"
val searchText = searchTextLiveData.value ?: ""
if (searchText.isNotEmpty()) {
query += " $searchText"
}
return query
}
}