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.entities.Feed
import com.readrops.db.entities.Folder
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
class GetFoldersWithFeeds(
private val database: Database,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) {
suspend fun get(accountId: Int): Map<Folder?, List<Feed>> = withContext(dispatcher) {
val foldersWithFeeds = mutableMapOf<Folder?, List<Feed>>()
val folders = database.newFolderDao().selectFoldersByAccount(accountId)
for (folder in folders) {
val feeds = database.newFeedDao().selectFeedsByFolder(folder.id)
for (feed in feeds) {
feed.unreadCount = database.newItemDao().selectUnreadCount(feed.id)
fun get(accountId: Int): Flow<Map<Folder?, List<Feed>>> {
return combine(
flow = database.newFolderDao()
.selectFoldersAndFeeds(accountId),
flow2 = database.newFeedDao()
.selectFeedsWithoutFolder(accountId)
) { folders, feedsWithoutFolder ->
val foldersWithFeeds = folders.groupBy(
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 {
it.copy(
foldersAndFeeds = getFoldersWithFeeds.get(account.id),
items = ItemState.Loaded(
items = Pager(
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.Query
import com.readrops.db.entities.Feed
import com.readrops.db.pojo.FeedWithCount
import kotlinx.coroutines.flow.Flow
@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")
abstract suspend fun feedExists(feedUrl: String, accountId: Int): Boolean
@Query("Select * From Feed Where folder_id = :folderId")
abstract suspend fun selectFeedsByFolder(folderId: Int): List<Feed>
@Query("Select *, count(*) as unreadCount From Feed Inner Join Item On Feed.id = Item.feed_id " +
"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.Query
import com.readrops.db.entities.Folder
import com.readrops.db.pojo.FolderWithFeed
import kotlinx.coroutines.flow.Flow
@Dao
abstract class NewFolderDao : NewBaseDao<Folder> {
@Query("Select * From Folder Where account_id = :accountId Order By name ASC")
abstract suspend fun selectFoldersByAccount(accountId: Int): List<Folder>
@Query("Select Folder.id As folderId, Folder.name as folderName, Feed.id As feedId, Feed.name AS feedName, " +
"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
data class FeedWithFolder(
@Embedded(prefix = "feed_") val feed: Feed,
@Embedded(prefix = "folder_") val folder: Folder,
@Embedded(prefix = "feed_") val feed: Feed,
@Embedded(prefix = "folder_") val folder: Folder,
) : 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
)