diff --git a/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt b/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt index 94e838af..4127e2ec 100644 --- a/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt +++ b/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt @@ -5,6 +5,7 @@ import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder import com.readrops.db.filters.MainFilter import com.readrops.db.queries.FeedUnreadCountQueryBuilder +import com.readrops.db.queries.FoldersAndFeedsQueryBuilder import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -15,13 +16,15 @@ class GetFoldersWithFeeds( fun get( accountId: Int, mainFilter: MainFilter, - useSeparateState: Boolean + useSeparateState: Boolean, + hideReadFeeds: Boolean = false ): Flow>> { - val query = FeedUnreadCountQueryBuilder.build(accountId, mainFilter, useSeparateState) + val foldersAndFeedsQuery = FoldersAndFeedsQueryBuilder.build(accountId, hideReadFeeds) + val unreadItemsCountQuery = FeedUnreadCountQueryBuilder.build(accountId, mainFilter, useSeparateState) return combine( - flow = database.folderDao().selectFoldersAndFeeds(accountId), - flow2 = database.itemDao().selectFeedUnreadItemsCount(query) + flow = database.folderDao().selectFoldersAndFeeds(foldersAndFeedsQuery), + flow2 = database.itemDao().selectFeedUnreadItemsCount(unreadItemsCountQuery) ) { folders, itemCounts -> val foldersWithFeeds = folders.groupBy( keySelector = { diff --git a/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt b/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt index 738aca73..d3ada4bf 100644 --- a/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt +++ b/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt @@ -85,11 +85,15 @@ class TimelineScreenModel( ) } - getFoldersWithFeeds.get( - account.id, - filters.mainFilter, - account.config.useSeparateState - ) + preferences.hideReadFeeds.flow + .flatMapLatest { hideReadFeeds -> + getFoldersWithFeeds.get( + accountId = account.id, + mainFilter = filters.mainFilter, + useSeparateState = account.config.useSeparateState, + hideReadFeeds = hideReadFeeds + ) + } .collect { foldersAndFeeds -> _timelineState.update { it.copy( diff --git a/db/src/main/java/com/readrops/db/dao/FolderDao.kt b/db/src/main/java/com/readrops/db/dao/FolderDao.kt index 57681bd6..276787d6 100644 --- a/db/src/main/java/com/readrops/db/dao/FolderDao.kt +++ b/db/src/main/java/com/readrops/db/dao/FolderDao.kt @@ -2,8 +2,12 @@ package com.readrops.db.dao import androidx.room.Dao import androidx.room.Query +import androidx.room.RawQuery import androidx.room.Transaction +import androidx.sqlite.db.SupportSQLiteQuery +import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder +import com.readrops.db.entities.Item import com.readrops.db.entities.account.Account import com.readrops.db.pojo.FolderWithFeed import kotlinx.coroutines.flow.Flow @@ -11,20 +15,9 @@ import kotlinx.coroutines.flow.Flow @Dao interface FolderDao : BaseDao { - @Query(""" - Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl, - Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Feed.remoteId as feedRemoteId, Folder.id As folderId, - Folder.name As folderName, Feed.account_id as accountId, Folder.remoteId as folderRemoteId - From Feed Left Join Folder On Folder.id = Feed.folder_id - Where Feed.folder_id is NULL OR Feed.folder_id is NOT NULL And Feed.id is NULL Or Feed.id is NOT NULL And Feed.account_id = :accountId Group By Feed.id - UNION ALL - Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl, - Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Feed.remoteId as feedRemoteId, Folder.id As folderId, - Folder.name As folderName, Folder.account_id as accountId, Folder.remoteId as folderRemoteId - From Folder Left Join Feed On Folder.id = Feed.folder_id - Where Feed.id is NULL And Folder.account_id = :accountId - """) - fun selectFoldersAndFeeds(accountId: Int): Flow> + // TODO react to Item changes when this table is not part of the query might be a perf issue + @RawQuery(observedEntities = [Folder::class, Feed::class, Item::class]) + fun selectFoldersAndFeeds(query: SupportSQLiteQuery): Flow> @Query("Select * From Folder Where account_id = :accountId") fun selectFolders(accountId: Int): Flow> diff --git a/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt b/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt new file mode 100644 index 00000000..53d63e20 --- /dev/null +++ b/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt @@ -0,0 +1,73 @@ +package com.readrops.db.queries + +import androidx.sqlite.db.SimpleSQLiteQuery +import androidx.sqlite.db.SupportSQLiteQuery +import androidx.sqlite.db.SupportSQLiteQueryBuilder + +object FoldersAndFeedsQueryBuilder { + + private val COLUMNS = arrayOf( + "Feed.id As feedId", + "Feed.name As feedName", + "Feed.icon_url As feedIcon", + "Feed.url As feedUrl", + "Feed.siteUrl As feedSiteUrl", + "Feed.description as feedDescription", + "Feed.remoteId as feedRemoteId", + "Folder.id As folderId", + "Folder.name As folderName", + "Feed.account_id as accountId", + "Folder.remoteId as folderRemoteId" + ) + + private val FEED_JOIN = """(Select * From Feed Where account_id = :accountId) Feed + Left Join Folder On Folder.id = Feed.folder_id """.trimMargin() + + private const val FOLDER_JOIN = "Folder Left Join Feed On Folder.id = Feed.folder_id " + + private const val ITEM_JOIN = " Inner Join Item On Item.feed_id = Feed.id " + + private const val FEED_SELECTION = "Feed.folder_id is NULL OR Feed.folder_id is NOT NULL " + + private const val FOLDER_SELECTION = "Feed.id is NULL And Folder.account_id = :accountId" + + private const val ITEM_SELECTION = "And Item.read = 0" + + fun build(accountId: Int, hideReadFeeds: Boolean = false): SupportSQLiteQuery { + return SimpleSQLiteQuery( + """ + ${buildFeedQuery(accountId, hideReadFeeds).sql} + ${ + if (!hideReadFeeds) { + """UNION ALL + ${buildFolderQuery(accountId).sql} + """.trimIndent() + } else { + "" + } + }""".trimIndent() + ) + } + + private fun buildFeedQuery(accountId: Int, hideReadFeeds: Boolean): SupportSQLiteQuery { + val tables = if (hideReadFeeds) FEED_JOIN + ITEM_JOIN else FEED_JOIN + val selection = if (hideReadFeeds) FEED_SELECTION + ITEM_SELECTION else FEED_SELECTION + + return SupportSQLiteQueryBuilder.builder(tables.replace(":accountId", "$accountId")).run { + columns(COLUMNS) + selection(selection, null) + groupBy("Feed.id") + + create() + } + } + + private fun buildFolderQuery(accountId: Int): SupportSQLiteQuery { + return SupportSQLiteQueryBuilder.builder(FOLDER_JOIN).run { + columns(COLUMNS) + selection(FOLDER_SELECTION.replace(":accountId", "$accountId"), null) + + create() + } + } +} \ No newline at end of file