diff --git a/appcompose/build.gradle b/appcompose/build.gradle index 1c4e69ec..577541f5 100644 --- a/appcompose/build.gradle +++ b/appcompose/build.gradle @@ -106,4 +106,6 @@ dependencies { implementation "io.coil-kt:coil:2.4.0" implementation "io.coil-kt:coil-compose:2.4.0" + + androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4" } \ No newline at end of file diff --git a/appcompose/src/androidTest/java/com/readrops/app/compose/GetFoldersWithFeedsTest.kt b/appcompose/src/androidTest/java/com/readrops/app/compose/GetFoldersWithFeedsTest.kt new file mode 100644 index 00000000..b0b5ac2d --- /dev/null +++ b/appcompose/src/androidTest/java/com/readrops/app/compose/GetFoldersWithFeedsTest.kt @@ -0,0 +1,64 @@ +package com.readrops.app.compose + +import android.content.Context +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import com.readrops.app.compose.repositories.GetFoldersWithFeeds +import com.readrops.db.Database +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.entities.account.AccountType +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.runTest +import org.joda.time.LocalDateTime +import org.junit.Before +import org.junit.Test +import kotlin.test.assertTrue + +class GetFoldersWithFeedsTest { + + private lateinit var database: Database + private lateinit var getFoldersWithFeeds: GetFoldersWithFeeds + private val account = Account(accountType = AccountType.LOCAL) + + @Before + fun before() { + val context = ApplicationProvider.getApplicationContext() + database = Room.inMemoryDatabaseBuilder(context, Database::class.java).build() + + runTest { + account.id = database.newAccountDao().insert(account).toInt() + + repeat(3) { time -> + database.newFolderDao().insert(Folder(name = "Folder $time", accountId = account.id)) + } + + repeat(2) { time -> + database.newFeedDao().insert(Feed(name = "Feed $time", accountId = account.id)) + } + + repeat(2) { time -> + database.newFeedDao().insert(Feed(name = "Feed ${time+2}", folderId = 1, accountId = account.id)) + } + + repeat(3) { time -> + database.newItemDao().insert(Item(title = "Item $time", feedId = 1, pubDate = LocalDateTime.now())) + } + } + } + + @Test + fun getFoldersWithFeedsTest() = runTest { + getFoldersWithFeeds = GetFoldersWithFeeds(database, StandardTestDispatcher(testScheduler)) + val foldersAndFeeds = getFoldersWithFeeds.get(account.id) + + assertTrue { foldersAndFeeds.size == 4 } + assertTrue { foldersAndFeeds.entries.first().value.size == 2 } + assertTrue { foldersAndFeeds.entries.last().key == null } + assertTrue { foldersAndFeeds[null]!!.size == 2 } + assertTrue { foldersAndFeeds[null]!!.first().unreadCount == 3 } + + } +} \ No newline at end of file diff --git a/appcompose/src/main/java/com/readrops/app/compose/repositories/GetFoldersWithFeeds.kt b/appcompose/src/main/java/com/readrops/app/compose/repositories/GetFoldersWithFeeds.kt new file mode 100644 index 00000000..0c8fd786 --- /dev/null +++ b/appcompose/src/main/java/com/readrops/app/compose/repositories/GetFoldersWithFeeds.kt @@ -0,0 +1,37 @@ +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 + +class GetFoldersWithFeeds( + private val database: Database, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + + suspend fun get(accountId: Int): Map> = withContext(dispatcher) { + val foldersWithFeeds = mutableMapOf>() + 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) + } + + foldersWithFeeds[folder] = feeds + } + + val feedsAlone = database.newFeedDao().selectFeedsAlone(accountId) + for (feed in feedsAlone) { + feed.unreadCount = database.newItemDao().selectUnreadCount(feed.id) + } + + foldersWithFeeds[null] = feedsAlone + foldersWithFeeds.toSortedMap(nullsLast()) + } +} \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/Database.kt b/db/src/main/java/com/readrops/db/Database.kt index 8b6c9834..02ce75ab 100644 --- a/db/src/main/java/com/readrops/db/Database.kt +++ b/db/src/main/java/com/readrops/db/Database.kt @@ -6,6 +6,7 @@ import androidx.room.TypeConverters import com.readrops.db.dao.* import com.readrops.db.dao.newdao.NewAccountDao import com.readrops.db.dao.newdao.NewFeedDao +import com.readrops.db.dao.newdao.NewFolderDao import com.readrops.db.dao.newdao.NewItemDao import com.readrops.db.entities.* import com.readrops.db.entities.account.Account @@ -35,4 +36,6 @@ abstract class Database : RoomDatabase() { abstract fun newItemDao(): NewItemDao abstract fun newAccountDao(): NewAccountDao + + abstract fun newFolderDao(): NewFolderDao } \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/dao/newdao/NewFeedDao.kt b/db/src/main/java/com/readrops/db/dao/newdao/NewFeedDao.kt index 471fefca..d66102fb 100644 --- a/db/src/main/java/com/readrops/db/dao/newdao/NewFeedDao.kt +++ b/db/src/main/java/com/readrops/db/dao/newdao/NewFeedDao.kt @@ -19,4 +19,10 @@ abstract class NewFeedDao : NewBaseDao { @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 + + @Query("Select * From Feed Where account_id = :accountId And folder_id Is Null") + abstract suspend fun selectFeedsAlone(accountId: Int): List } \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/dao/newdao/NewFolderDao.kt b/db/src/main/java/com/readrops/db/dao/newdao/NewFolderDao.kt new file mode 100644 index 00000000..c9e40e2c --- /dev/null +++ b/db/src/main/java/com/readrops/db/dao/newdao/NewFolderDao.kt @@ -0,0 +1,14 @@ +package com.readrops.db.dao.newdao + +import androidx.room.Dao +import androidx.room.Query +import com.readrops.db.entities.Folder + +@Dao +abstract class NewFolderDao : NewBaseDao { + + @Query("Select * From Folder Where account_id = :accountId Order By name ASC") + abstract suspend fun selectFoldersByAccount(accountId: Int): List + + +} \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/dao/newdao/NewItemDao.kt b/db/src/main/java/com/readrops/db/dao/newdao/NewItemDao.kt index 7d9e97eb..c7703ac8 100644 --- a/db/src/main/java/com/readrops/db/dao/newdao/NewItemDao.kt +++ b/db/src/main/java/com/readrops/db/dao/newdao/NewItemDao.kt @@ -1,6 +1,7 @@ package com.readrops.db.dao.newdao import androidx.room.Dao +import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery import com.readrops.db.entities.Feed @@ -16,5 +17,7 @@ abstract class NewItemDao : NewBaseDao { @RawQuery(observedEntities = [Item::class, Feed::class, Folder::class, ItemState::class]) abstract fun selectAll(query: SupportSQLiteQuery): Flow> + @Query("Select count(*) From Item Where feed_id = :feedId And read = 0") + abstract fun selectUnreadCount(feedId: Int): Int } \ No newline at end of file