diff --git a/android/Omnivore/app/src/main/graphql/ArticleContent.graphql b/android/Omnivore/app/src/main/graphql/ArticleContent.graphql index e33ab6705..fc7a2b788 100644 --- a/android/Omnivore/app/src/main/graphql/ArticleContent.graphql +++ b/android/Omnivore/app/src/main/graphql/ArticleContent.graphql @@ -21,6 +21,7 @@ query GetArticle($slug: String!) { fragment ArticleFields on Article { id title + folder url author image diff --git a/android/Omnivore/app/src/main/graphql/Search.graphql b/android/Omnivore/app/src/main/graphql/Search.graphql index a626a9e09..595d8324f 100644 --- a/android/Omnivore/app/src/main/graphql/Search.graphql +++ b/android/Omnivore/app/src/main/graphql/Search.graphql @@ -1,56 +1,57 @@ query Search($after: String, $first: Int, $query: String) { - search(first: $first, after: $after, query: $query, includeContent: true) { - ... on SearchSuccess { - edges { - cursor - node { - id - title - slug - url - pageType - contentReader - createdAt - isArchived - readingProgressPercent - readingProgressAnchorIndex - author - image - description - publishedAt - ownedByViewer - originalArticleUrl - uploadFileId - labels { - ...LabelFields - } - highlights { - ...HighlightFields - } - pageId - shortId - quote - annotation - state - siteName - subscription - readAt - savedAt - updatedAt - wordsCount - content + search(first: $first, after: $after, query: $query, includeContent: true) { + ... on SearchSuccess { + edges { + cursor + node { + id + title + slug + url + folder + pageType + contentReader + createdAt + isArchived + readingProgressPercent + readingProgressAnchorIndex + author + image + description + publishedAt + ownedByViewer + originalArticleUrl + uploadFileId + labels { + ...LabelFields + } + highlights { + ...HighlightFields + } + pageId + shortId + quote + annotation + state + siteName + subscription + readAt + savedAt + updatedAt + wordsCount + content + } + } + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + totalCount + } + } + ... on SearchError { + errorCodes } - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - totalCount - } } - ... on SearchError { - errorCodes - } - } } diff --git a/android/Omnivore/app/src/main/graphql/UpdatesSince.graphql b/android/Omnivore/app/src/main/graphql/UpdatesSince.graphql index 97148a176..8055d2199 100644 --- a/android/Omnivore/app/src/main/graphql/UpdatesSince.graphql +++ b/android/Omnivore/app/src/main/graphql/UpdatesSince.graphql @@ -13,6 +13,7 @@ query UpdatesSince( node { id title + folder slug url pageType diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/LibrarySync.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/LibrarySync.kt index cc09884b2..639a9a903 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/LibrarySync.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/LibrarySync.kt @@ -49,6 +49,7 @@ suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): S val savedItem = SavedItem( savedItemId = it.id, title = it.title, + folder = it.folder, createdAt = it.createdAt as String, savedAt = it.savedAt as String, readAt = it.readAt as String?, diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/model/LibraryQuery.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/model/LibraryQuery.kt index fe33fa46b..e6f56f4b2 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/model/LibraryQuery.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/model/LibraryQuery.kt @@ -1,6 +1,7 @@ package app.omnivore.omnivore.core.data.model data class LibraryQuery( + val folders: List, val allowedArchiveStates: List, val sortKey: String, val requiredLabels: List, diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/repository/impl/LibraryRepositoryImpl.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/repository/impl/LibraryRepositoryImpl.kt index d48f88c81..989d3fe89 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/repository/impl/LibraryRepositoryImpl.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/data/repository/impl/LibraryRepositoryImpl.kt @@ -61,6 +61,7 @@ class LibraryRepositoryImpl @Inject constructor( override fun getSavedItems(query: LibraryQuery): Flow> = savedItemDao.filteredLibraryData( + folders = query.folders, query.allowedArchiveStates, query.sortKey, hasRequiredLabels = query.requiredLabels.size, @@ -418,6 +419,7 @@ class LibraryRepositoryImpl @Inject constructor( val savedItem = SavedItem( savedItemId = it.id, title = it.title, + folder = it.folder, createdAt = it.createdAt as String, savedAt = it.savedAt as String, readAt = it.readAt as String?, diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/OmnivoreDatabase.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/OmnivoreDatabase.kt index ed292707a..93ccfbbd1 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/OmnivoreDatabase.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/OmnivoreDatabase.kt @@ -27,7 +27,7 @@ import app.omnivore.omnivore.core.database.entities.ViewerDao HighlightChange::class, SavedItemAndSavedItemLabelCrossRef::class, SavedItemAndHighlightCrossRef::class], - version = 26, + version = 27, exportSchema = true ) abstract class OmnivoreDatabase : RoomDatabase() { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/dao/SavedItemDao.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/dao/SavedItemDao.kt index e8463717e..650cedde4 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/dao/SavedItemDao.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/dao/SavedItemDao.kt @@ -77,6 +77,7 @@ interface SavedItemDao { "LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " + "WHERE SavedItem.serverSyncStatus != 2 " + + "AND SavedItem.folder IN (:folders) " + "AND SavedItem.isArchived IN (:allowedArchiveStates) " + "AND SavedItem.contentReader IN (:allowedContentReaders) " + "AND CASE WHEN :hasRequiredLabels THEN SavedItemLabel.name in (:requiredLabels) ELSE 1 END " + @@ -97,6 +98,7 @@ interface SavedItemDao { "CASE WHEN :sortKey = 'recentlyPublished' THEN SavedItem.publishDate END DESC" ) fun filteredLibraryData( + folders: List, allowedArchiveStates: List, sortKey: String, hasRequiredLabels: Int, diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/entities/SavedItem.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/entities/SavedItem.kt index 92e72cabb..fd2796f0a 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/entities/SavedItem.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/database/entities/SavedItem.kt @@ -9,6 +9,7 @@ import androidx.room.PrimaryKey data class SavedItem( @PrimaryKey val savedItemId: String, val title: String, + val folder: String, val createdAt: String, val savedAt: String, val readAt: String?, @@ -71,12 +72,10 @@ data class TypeaheadCardData( ) object SavedItemQueryConstants { - const val columns = - "savedItemId, slug, publisherURLString, title, author, descriptionText, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount" const val libraryColumns = "SavedItem.savedItemId, " + "SavedItem.slug, " + "SavedItem.createdAt, " + - + "SavedItem.folder, " + "SavedItem.publisherURLString, " + "SavedItem.title, " + "SavedItem.author, " + diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SavedItemQuery.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SavedItemQuery.kt index 856b1d8ea..f463890ca 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SavedItemQuery.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SavedItemQuery.kt @@ -1,110 +1,117 @@ package app.omnivore.omnivore.core.network import android.util.Log -import app.omnivore.omnivore.graphql.generated.GetArticleQuery -import app.omnivore.omnivore.graphql.generated.type.ContentReader +import app.omnivore.omnivore.core.database.entities.Highlight import app.omnivore.omnivore.core.database.entities.SavedItem import app.omnivore.omnivore.core.database.entities.SavedItemLabel -import app.omnivore.omnivore.core.database.entities.Highlight +import app.omnivore.omnivore.graphql.generated.GetArticleQuery +import app.omnivore.omnivore.graphql.generated.type.ContentReader import java.io.File import java.net.URL import java.nio.file.Files import java.nio.file.StandardCopyOption data class SavedItemQueryResponse( - val item: SavedItem?, - val highlights: List, - val labels: List, - val state: String + val item: SavedItem?, + val highlights: List, + val labels: List, + val state: String ) { - companion object { - fun emptyResponse(): SavedItemQueryResponse { - return SavedItemQueryResponse(null, listOf(), listOf(), state = "") + companion object { + fun emptyResponse(): SavedItemQueryResponse { + return SavedItemQueryResponse(null, listOf(), listOf(), state = "") + } } - } } suspend fun Networker.savedItem(slug: String): SavedItemQueryResponse { - try { - val result = authenticatedApolloClient().query( - GetArticleQuery(slug = slug) - ).execute() + try { + val result = authenticatedApolloClient().query( + GetArticleQuery(slug = slug) + ).execute() - val article = result.data?.article?.onArticleSuccess?.article - ?: return SavedItemQueryResponse.emptyResponse() + val article = result.data?.article?.onArticleSuccess?.article + ?: return SavedItemQueryResponse.emptyResponse() - val labels = article.labels ?: listOf() + val labels = article.labels ?: listOf() - val savedItemLabels = labels.map { - SavedItemLabel( - savedItemLabelId = it.labelFields.id, - name = it.labelFields.name, - color = it.labelFields.color, - createdAt = it.labelFields.createdAt as String?, - labelDescription = it.labelFields.description - ) - } + val savedItemLabels = labels.map { + SavedItemLabel( + savedItemLabelId = it.labelFields.id, + name = it.labelFields.name, + color = it.labelFields.color, + createdAt = it.labelFields.createdAt as String?, + labelDescription = it.labelFields.description + ) + } - val highlights = article.highlights.map { + val highlights = article.highlights.map { // val updatedAtString = it.highlightFields.updatedAt as? String - Highlight( - highlightId = it.highlightFields.id, - type = it.highlightFields.type.toString(), - shortId = it.highlightFields.shortId, - quote = it.highlightFields.quote, - prefix = it.highlightFields.prefix, - suffix = it.highlightFields.suffix, - patch = it.highlightFields.patch, - annotation = it.highlightFields.annotation, - createdAt = it.highlightFields.createdAt as String?, - updatedAt = it.highlightFields.updatedAt as String?, - createdByMe = it.highlightFields.createdByMe, - color = it.highlightFields.color, - highlightPositionPercent = it.highlightFields.highlightPositionPercent, - highlightPositionAnchorIndex = it.highlightFields.highlightPositionAnchorIndex - ) + Highlight( + highlightId = it.highlightFields.id, + type = it.highlightFields.type.toString(), + shortId = it.highlightFields.shortId, + quote = it.highlightFields.quote, + prefix = it.highlightFields.prefix, + suffix = it.highlightFields.suffix, + patch = it.highlightFields.patch, + annotation = it.highlightFields.annotation, + createdAt = it.highlightFields.createdAt as String?, + updatedAt = it.highlightFields.updatedAt as String?, + createdByMe = it.highlightFields.createdByMe, + color = it.highlightFields.color, + highlightPositionPercent = it.highlightFields.highlightPositionPercent, + highlightPositionAnchorIndex = it.highlightFields.highlightPositionAnchorIndex + ) + } + + var localPDFPath: String? = null + if (article.articleFields.contentReader == ContentReader.PDF) { + // download the PDF and save it locally + // article.articleFields.url + + val localFile = File.createTempFile("pdf-" + article.articleFields.id, ".pdf") + val url = URL(article.articleFields.url) + Log.d("pdf", "creating local file: $localFile") + + url.openStream() + .use { Files.copy(it, localFile.toPath(), StandardCopyOption.REPLACE_EXISTING) } + localPDFPath = localFile.toPath().toString() + } + + val savedItem = SavedItem( + savedItemId = article.articleFields.id, + title = article.articleFields.title, + folder = article.articleFields.folder, + createdAt = article.articleFields.createdAt as String, + savedAt = article.articleFields.savedAt as String, + readAt = article.articleFields.readAt as String?, + updatedAt = article.articleFields.updatedAt as String?, + readingProgress = article.articleFields.readingProgressPercent, + readingProgressAnchor = article.articleFields.readingProgressAnchorIndex, + imageURLString = article.articleFields.image, + pageURLString = article.articleFields.url, + descriptionText = article.articleFields.description, + publisherURLString = article.articleFields.originalArticleUrl, + siteName = article.articleFields.siteName, + author = article.articleFields.author, + publishDate = article.articleFields.publishedAt as String?, + slug = article.articleFields.slug, + isArchived = article.articleFields.isArchived, + contentReader = article.articleFields.contentReader.rawValue, + content = article.articleFields.content, + wordsCount = article.articleFields.wordsCount, + localPDFPath = localPDFPath + ) + + return SavedItemQueryResponse( + item = savedItem, + highlights, + labels = savedItemLabels, + state = article.articleFields.state?.rawValue ?: "" + ) + } catch (e: java.lang.Exception) { + return SavedItemQueryResponse(item = null, listOf(), labels = listOf(), state = "") } - - var localPDFPath: String? = null - if (article.articleFields.contentReader == ContentReader.PDF) { - // download the PDF and save it locally - // article.articleFields.url - - val localFile = File.createTempFile("pdf-" + article.articleFields.id, ".pdf", ) - val url = URL(article.articleFields.url) - Log.d("pdf", "creating local file: $localFile") - - url.openStream().use { Files.copy(it, localFile.toPath(), StandardCopyOption.REPLACE_EXISTING) } - localPDFPath = localFile.toPath().toString() - } - - val savedItem = SavedItem( - savedItemId = article.articleFields.id, - title = article.articleFields.title, - createdAt = article.articleFields.createdAt as String, - savedAt = article.articleFields.savedAt as String, - readAt = article.articleFields.readAt as String?, - updatedAt = article.articleFields.updatedAt as String?, - readingProgress = article.articleFields.readingProgressPercent, - readingProgressAnchor = article.articleFields.readingProgressAnchorIndex, - imageURLString = article.articleFields.image, - pageURLString = article.articleFields.url, - descriptionText = article.articleFields.description, - publisherURLString = article.articleFields.originalArticleUrl, - siteName = article.articleFields.siteName, - author = article.articleFields.author, - publishDate = article.articleFields.publishedAt as String?, - slug = article.articleFields.slug, - isArchived = article.articleFields.isArchived, - contentReader = article.articleFields.contentReader.rawValue, - content = article.articleFields.content, - wordsCount = article.articleFields.wordsCount, - localPDFPath = localPDFPath - ) - - return SavedItemQueryResponse(item = savedItem, highlights, labels = savedItemLabels, state = article.articleFields.state?.rawValue ?: "") - } catch (e: java.lang.Exception) { - return SavedItemQueryResponse(item = null, listOf(), labels = listOf(), state = "") - } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SearchQuery.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SearchQuery.kt index 4694dd48d..93307ddd0 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SearchQuery.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/network/SearchQuery.kt @@ -1,100 +1,91 @@ package app.omnivore.omnivore.core.network +import app.omnivore.omnivore.core.data.model.ServerSyncStatus import app.omnivore.omnivore.core.database.entities.Highlight import app.omnivore.omnivore.core.database.entities.SavedItem import app.omnivore.omnivore.core.database.entities.SavedItemLabel import app.omnivore.omnivore.graphql.generated.SearchQuery -import app.omnivore.omnivore.core.data.model.ServerSyncStatus import com.apollographql.apollo3.api.Optional data class LibrarySearchQueryResponse( - val cursor: String?, - val items: List + val cursor: String?, val items: List ) data class LibrarySearchItem( - val item: SavedItem, - val labels: List, - val highlights: List + val item: SavedItem, val labels: List, val highlights: List ) suspend fun Networker.search( - cursor: String? = null, - limit: Int = 15, - query: String + cursor: String? = null, limit: Int = 15, query: String ): LibrarySearchQueryResponse { - try { - val result = authenticatedApolloClient().query( - SearchQuery( - after = Optional.presentIfNotNull(cursor), - first = Optional.presentIfNotNull(limit), - query = Optional.presentIfNotNull(query) - ) - ).execute() + try { + val result = authenticatedApolloClient().query( + SearchQuery( + after = Optional.presentIfNotNull(cursor), + first = Optional.presentIfNotNull(limit), + query = Optional.presentIfNotNull(query) + ) + ).execute() - val newCursor = result.data?.search?.onSearchSuccess?.pageInfo?.endCursor - val itemList = result.data?.search?.onSearchSuccess?.edges ?: listOf() + val newCursor = result.data?.search?.onSearchSuccess?.pageInfo?.endCursor + val itemList = result.data?.search?.onSearchSuccess?.edges ?: listOf() - 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 = it.node.content, - wordsCount = it.node.wordsCount, - ), - labels = (it.node.labels ?: listOf()).map { label -> - SavedItemLabel( - savedItemLabelId = label.labelFields.id, - name = label.labelFields.name, - color = label.labelFields.color, - createdAt = label.labelFields.createdAt as String?, - labelDescription = null - ) - }, - highlights = (it.node.highlights ?: listOf()).map { highlight -> - Highlight( - highlightId = highlight.highlightFields.id, - type = highlight.highlightFields.type.toString(), - annotation = highlight.highlightFields.annotation, - createdByMe = highlight.highlightFields.createdByMe, - patch = highlight.highlightFields.patch, - prefix = highlight.highlightFields.prefix, - quote = highlight.highlightFields.quote, - serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue, - shortId = highlight.highlightFields.shortId, - suffix = highlight.highlightFields.suffix, - updatedAt = highlight.highlightFields.updatedAt as String?, - createdAt = highlight.highlightFields.createdAt as String?, - color = highlight.highlightFields.color, - highlightPositionPercent = highlight.highlightFields.highlightPositionPercent, - highlightPositionAnchorIndex = highlight.highlightFields.highlightPositionAnchorIndex - ) + val searchItems = itemList.map { + LibrarySearchItem(item = SavedItem( + savedItemId = it.node.id, + title = it.node.title, + folder = it.node.folder, + 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 = it.node.content, + wordsCount = it.node.wordsCount + ), labels = (it.node.labels ?: listOf()).map { label -> + SavedItemLabel( + savedItemLabelId = label.labelFields.id, + name = label.labelFields.name, + color = label.labelFields.color, + createdAt = label.labelFields.createdAt as String?, + labelDescription = null + ) + }, highlights = (it.node.highlights ?: listOf()).map { highlight -> + Highlight( + highlightId = highlight.highlightFields.id, + type = highlight.highlightFields.type.toString(), + annotation = highlight.highlightFields.annotation, + createdByMe = highlight.highlightFields.createdByMe, + patch = highlight.highlightFields.patch, + prefix = highlight.highlightFields.prefix, + quote = highlight.highlightFields.quote, + serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue, + shortId = highlight.highlightFields.shortId, + suffix = highlight.highlightFields.suffix, + updatedAt = highlight.highlightFields.updatedAt as String?, + createdAt = highlight.highlightFields.createdAt as String?, + color = highlight.highlightFields.color, + highlightPositionPercent = highlight.highlightFields.highlightPositionPercent, + highlightPositionAnchorIndex = highlight.highlightFields.highlightPositionAnchorIndex + ) + }) } - ) - } - return LibrarySearchQueryResponse( - cursor = newCursor, - items = searchItems - ) - } catch (e: java.lang.Exception) { - return LibrarySearchQueryResponse(null, listOf()) - } + return LibrarySearchQueryResponse( + cursor = newCursor, items = searchItems + ) + } catch (e: java.lang.Exception) { + return LibrarySearchQueryResponse(null, listOf()) + } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/following/FollowingViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/following/FollowingViewModel.kt index dbd7d2280..8c63aef4a 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/following/FollowingViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/following/FollowingViewModel.kt @@ -55,9 +55,10 @@ class FollowingViewModel @Inject constructor( private val _libraryQuery = MutableStateFlow( LibraryQuery( + folders = listOf("following"), allowedArchiveStates = listOf(0), sortKey = "newest", - requiredLabels = listOf("Newsletter", "RSS"), + requiredLabels = listOf(), excludedLabels = listOf(), allowedContentReaders = listOf("WEB", "PDF", "EPUB") ) @@ -148,7 +149,8 @@ class FollowingViewModel @Inject constructor( fun loadUsingSearchAPI() { viewModelScope.launch { val result = libraryRepository.librarySearch( - cursor = librarySearchCursor, query = searchQueryString() + cursor = librarySearchCursor, + query = searchQueryString() ) result.cursor?.let { librarySearchCursor = it @@ -225,6 +227,7 @@ class FollowingViewModel @Inject constructor( } _libraryQuery.value = LibraryQuery( + folders = listOf("following"), allowedArchiveStates = allowedArchiveStates, sortKey = sortKey, requiredLabels = requiredLabels, @@ -367,7 +370,7 @@ class FollowingViewModel @Inject constructor( private fun searchQueryString(): String { var query = - "${appliedFilterState.value?.queryString} ${appliedSortFilterLiveData.value?.queryString}" + "${appliedFilterState.value.queryString} ${appliedSortFilterLiveData.value.queryString}" activeLabels.value.let { if (it.isNotEmpty()) { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryViewModel.kt index 7345c41cd..0aa31d10e 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryViewModel.kt @@ -13,6 +13,7 @@ import app.omnivore.omnivore.core.data.repository.LibraryRepository import app.omnivore.omnivore.core.database.entities.SavedItemLabel import app.omnivore.omnivore.core.database.entities.SavedItemWithLabelsAndHighlights import app.omnivore.omnivore.core.datastore.DatastoreRepository +import app.omnivore.omnivore.core.datastore.followingTabActive import app.omnivore.omnivore.core.datastore.lastUsedSavedItemFilter import app.omnivore.omnivore.core.datastore.lastUsedSavedItemSortFilter import app.omnivore.omnivore.core.datastore.libraryLastSyncTimestamp @@ -37,7 +38,7 @@ import javax.inject.Inject @OptIn(ExperimentalCoroutinesApi::class) @HiltViewModel class LibraryViewModel @Inject constructor( - private val datastoreRepo: DatastoreRepository, + private val datastoreRepository: DatastoreRepository, private val libraryRepository: LibraryRepository, @ApplicationContext private val applicationContext: Context ) : ViewModel(), SavedItemViewModel { @@ -48,16 +49,42 @@ class LibraryViewModel @Inject constructor( var snackbarMessage by mutableStateOf(null) private set + private val folders = MutableStateFlow(listOf()) + private val _libraryQuery = MutableStateFlow( LibraryQuery( + folders = folders.value, allowedArchiveStates = listOf(0), sortKey = "newest", requiredLabels = listOf(), - excludedLabels = listOf("Newsletter", "RSS"), + excludedLabels = listOf(), allowedContentReaders = listOf("WEB", "PDF", "EPUB") ) ) + private val followingTabActiveState: StateFlow = datastoreRepository.getBoolean(followingTabActive).stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(), + initialValue = false + ) + + private fun updateLibraryQuery() { + _libraryQuery.value = _libraryQuery.value.copy(folders = folders.value) + } + + init { + viewModelScope.launch { + followingTabActiveState.collect { tabActive -> + if (tabActive) { + folders.value = listOf("inbox") + } else { + folders.value = listOf("inbox","following") + } + updateLibraryQuery() + } + } + } + val uiState: StateFlow = _libraryQuery.flatMapLatest { query -> libraryRepository.getSavedItems(query) }.map(LibraryUiState::Success).stateIn( @@ -114,7 +141,7 @@ class LibraryViewModel @Inject constructor( } private fun getLastSyncTime(): Instant? = runBlocking { - datastoreRepo.getString(libraryLastSyncTimestamp)?.let { + datastoreRepository.getString(libraryLastSyncTimestamp)?.let { try { return@let Instant.parse(it) } catch (e: Exception) { @@ -142,7 +169,8 @@ class LibraryViewModel @Inject constructor( fun loadUsingSearchAPI() { viewModelScope.launch { val result = libraryRepository.librarySearch( - cursor = librarySearchCursor, query = searchQueryString() + cursor = librarySearchCursor, + query = searchQueryString() ) result.cursor?.let { librarySearchCursor = it @@ -160,7 +188,7 @@ class LibraryViewModel @Inject constructor( fun updateSavedItemFilter(filter: SavedItemFilter) { viewModelScope.launch { - datastoreRepo.putString(lastUsedSavedItemFilter, filter.rawValue) + datastoreRepository.putString(lastUsedSavedItemFilter, filter.rawValue) appliedFilterState.value = filter handleFilterChanges() } @@ -168,7 +196,7 @@ class LibraryViewModel @Inject constructor( fun updateSavedItemSortFilter(filter: SavedItemSortFilter) { viewModelScope.launch { - datastoreRepo.putString(lastUsedSavedItemSortFilter, filter.rawValue) + datastoreRepository.putString(lastUsedSavedItemSortFilter, filter.rawValue) appliedSortFilterLiveData.value = filter handleFilterChanges() } @@ -214,10 +242,11 @@ class LibraryViewModel @Inject constructor( val excludeLabels = when (appliedFilterState.value) { SavedItemFilter.NON_FEED -> listOf("Newsletter", "RSS") - else -> listOf("Newsletter", "RSS") + else -> listOf() } _libraryQuery.value = LibraryQuery( + folders = folders.value, allowedArchiveStates = allowedArchiveStates, sortKey = sortKey, requiredLabels = requiredLabels, @@ -269,7 +298,7 @@ class LibraryViewModel @Inject constructor( isInitialBatch = false ) } else { - datastoreRepo.putString(libraryLastSyncTimestamp, startTime) + datastoreRepository.putString(libraryLastSyncTimestamp, startTime) } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/profile/filters/FiltersScreen.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/profile/filters/FiltersScreen.kt index 70459c3e6..a75f7e0f2 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/profile/filters/FiltersScreen.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/profile/filters/FiltersScreen.kt @@ -53,8 +53,8 @@ internal fun FiltersScreen( SwitchPreferenceWidget( title = stringResource(R.string.hide_following_tab), - checked = followingTabActive, - onCheckedChanged = { filtersViewModel.setFollowingTabActiveState(it) }, + checked = !followingTabActive, + onCheckedChanged = { filtersViewModel.setFollowingTabActiveState(!it) }, ) } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt index c8a61afd9..4c4df4f30 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt @@ -64,7 +64,7 @@ fun RootView( val navController = rememberNavController() val followingTabActive by loginViewModel.followingTabActiveState.collectAsStateWithLifecycle() - val destinations = if (!followingTabActive) { + val destinations = if (followingTabActive) { TopLevelDestination.entries } else { TopLevelDestination.entries.filter { it.route != Routes.Following.route }