Improve logic to build drawer folders and feeds list

* db requests down to 2
* react to changes when feeds/folders/items read state are modified
This commit is contained in:
Shinokuni 2023-08-27 15:48:33 +02:00
parent 36f768044a
commit 03ee5deab9
5 changed files with 68 additions and 34 deletions

View File

@ -3,35 +3,43 @@ package com.readrops.app.compose.repositories
import com.readrops.db.Database import com.readrops.db.Database
import com.readrops.db.entities.Feed import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder import com.readrops.db.entities.Folder
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.withContext
class GetFoldersWithFeeds( class GetFoldersWithFeeds(
private val database: Database, private val database: Database,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) { ) {
suspend fun get(accountId: Int): Map<Folder?, List<Feed>> = withContext(dispatcher) { fun get(accountId: Int): Flow<Map<Folder?, List<Feed>>> {
val foldersWithFeeds = mutableMapOf<Folder?, List<Feed>>() return combine(
val folders = database.newFolderDao().selectFoldersByAccount(accountId) flow = database.newFolderDao()
.selectFoldersAndFeeds(accountId),
for (folder in folders) { flow2 = database.newFeedDao()
val feeds = database.newFeedDao().selectFeedsByFolder(folder.id) .selectFeedsWithoutFolder(accountId)
) { folders, feedsWithoutFolder ->
for (feed in feeds) { val foldersWithFeeds = folders.groupBy(
feed.unreadCount = database.newItemDao().selectUnreadCount(feed.id) keySelector = { Folder(id = it.folderId, name = it.folderName) },
valueTransform = {
Feed(
id = it.feedId,
name = it.feedName,
iconUrl = it.feedIcon,
unreadCount = it.unreadCount
)
}
).mapValues { listEntry ->
if (listEntry.value.any { it.id == 0 }) {
listOf()
} else {
listEntry.value
}
} }
foldersWithFeeds[folder] = feeds foldersWithFeeds + mapOf(
Pair(
null,
feedsWithoutFolder.map { it.feed.apply { unreadCount = it.unreadCount } })
)
} }
val feedsAlone = database.newFeedDao().selectFeedsAlone(accountId)
for (feed in feedsAlone) {
feed.unreadCount = database.newItemDao().selectUnreadCount(feed.id)
}
foldersWithFeeds[null] = feedsAlone
foldersWithFeeds.toSortedMap(nullsLast())
} }
} }

View File

@ -49,7 +49,6 @@ class TimelineViewModel(
_timelineState.update { _timelineState.update {
it.copy( it.copy(
foldersAndFeeds = getFoldersWithFeeds.get(account.id),
items = ItemState.Loaded( items = ItemState.Loaded(
items = Pager( items = Pager(
config = PagingConfig( config = PagingConfig(
@ -64,6 +63,15 @@ class TimelineViewModel(
) )
) )
} }
getFoldersWithFeeds.get(account.id)
.collect { foldersAndFeeds ->
_timelineState.update {
it.copy(
foldersAndFeeds = foldersAndFeeds
)
}
}
} }
} }
} }

View File

@ -3,6 +3,7 @@ package com.readrops.db.dao.newdao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import com.readrops.db.entities.Feed import com.readrops.db.entities.Feed
import com.readrops.db.pojo.FeedWithCount
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
@ -20,9 +21,8 @@ abstract class NewFeedDao : NewBaseDao<Feed> {
@Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end") @Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end")
abstract suspend fun feedExists(feedUrl: String, accountId: Int): Boolean abstract suspend fun feedExists(feedUrl: String, accountId: Int): Boolean
@Query("Select * From Feed Where folder_id = :folderId") @Query("Select *, count(*) as unreadCount From Feed Inner Join Item On Feed.id = Item.feed_id " +
abstract suspend fun selectFeedsByFolder(folderId: Int): List<Feed> "Where Feed.folder_id is Null And Item.read = 0 And Feed.account_id = :accountId Group by Feed.id")
abstract fun selectFeedsWithoutFolder(accountId: Int): Flow<List<FeedWithCount>>
@Query("Select * From Feed Where account_id = :accountId And folder_id Is Null")
abstract suspend fun selectFeedsAlone(accountId: Int): List<Feed>
} }

View File

@ -3,12 +3,16 @@ package com.readrops.db.dao.newdao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import com.readrops.db.entities.Folder import com.readrops.db.entities.Folder
import com.readrops.db.pojo.FolderWithFeed
import kotlinx.coroutines.flow.Flow
@Dao @Dao
abstract class NewFolderDao : NewBaseDao<Folder> { abstract class NewFolderDao : NewBaseDao<Folder> {
@Query("Select * From Folder Where account_id = :accountId Order By name ASC") @Query("Select Folder.id As folderId, Folder.name as folderName, Feed.id As feedId, Feed.name AS feedName, " +
abstract suspend fun selectFoldersByAccount(accountId: Int): List<Folder> "Feed.icon_url As feedIcon, count(*) As unreadCount From Folder Left Join Feed " +
"On Folder.id = Feed.folder_id Left Join Item On Item.feed_id = Feed.id " +
"Where Feed.folder_id is NULL OR Feed.folder_id is NOT NULL And Item.read = 0 " +
"And Feed.account_id = :accountId Group By Feed.id, Folder.id Order By Folder.id")
abstract fun selectFoldersAndFeeds(accountId: Int): Flow<List<FolderWithFeed>>
} }

View File

@ -8,6 +8,20 @@ import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class FeedWithFolder( data class FeedWithFolder(
@Embedded(prefix = "feed_") val feed: Feed, @Embedded(prefix = "feed_") val feed: Feed,
@Embedded(prefix = "folder_") val folder: Folder, @Embedded(prefix = "folder_") val folder: Folder,
) : Parcelable ) : Parcelable
data class FolderWithFeed(
val folderId: Int,
val folderName: String,
val feedId: Int = 0,
val feedName: String? = null,
val feedIcon: String? = null,
val unreadCount: Int = 0
)
data class FeedWithCount(
@Embedded val feed: Feed,
val unreadCount: Int
)