Fetch FreshRSS folders and feeds

This commit is contained in:
Shinokuni 2024-05-04 21:44:05 +02:00
parent 0d69cfd66d
commit 36cdf84b34
6 changed files with 108 additions and 57 deletions

View File

@ -4,12 +4,13 @@ import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder
import com.readrops.db.entities.Item
class SyncResult(var items: List<Item> = mutableListOf(),
var starredItems: List<Item> = mutableListOf(),
var feeds: List<Feed> = listOf(),
var folders: List<Folder> = listOf(),
var unreadIds: List<String>? = null,
var readIds: List<String>? = null,
var starredIds: List<String>? = null,
var isError: Boolean = false
data class SyncResult(
var items: List<Item> = mutableListOf(),
var starredItems: List<Item> = mutableListOf(),
var feeds: List<Feed> = listOf(),
var folders: List<Folder> = listOf(),
var unreadIds: List<String>? = null,
var readIds: List<String>? = null,
var starredIds: List<String>? = null,
var isError: Boolean = false
)

View File

@ -1,7 +1,11 @@
package com.readrops.api.services.freshrss
import com.readrops.api.services.SyncResult
import com.readrops.api.services.freshrss.adapters.FreshRSSUserInfo
import com.readrops.db.entities.Item
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import okhttp3.MultipartBody
import java.io.StringReader
import java.util.Properties
@ -28,15 +32,19 @@ class NewFreshRSSDataSource(private val service: NewFreshRSSService) {
suspend fun getUserInfo(): FreshRSSUserInfo = service.userInfo()
suspend fun sync() {
suspend fun sync(): SyncResult = with(CoroutineScope(Dispatchers.IO)) {
return SyncResult().apply {
folders = async { getFolders() }.await()
feeds = async { getFeeds() }.await()
//items = async { getItems(listOf(GOOGLE_READ, GOOGLE_STARRED), MAX_ITEMS, null) }.await()
}
}
suspend fun getFolders() = service.getFolders()
suspend fun getFeeds() = service.getFeeds()
suspend fun getItems(excludeTargets: List<String>, max: Int, lastModified: Long): List<Item> {
suspend fun getItems(excludeTargets: List<String>, max: Int, lastModified: Long?): List<Item> {
return service.getItems(excludeTargets, max, lastModified)
}

View File

@ -6,6 +6,8 @@ import com.readrops.api.services.freshrss.NewFreshRSSDataSource
import com.readrops.api.utils.AuthInterceptor
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 org.koin.core.component.KoinComponent
@ -36,7 +38,14 @@ class FreshRSSRepository(
}
override suspend fun synchronize(): SyncResult {
TODO("Not yet implemented")
val syncResult = dataSource.sync().apply {
insertFolders(folders)
insertFeeds(feeds)
//insertItems(items)
}
return syncResult
}
override suspend fun insertNewFeeds(
@ -45,4 +54,18 @@ class FreshRSSRepository(
): ErrorResult {
TODO("Not yet implemented")
}
private suspend fun insertFeeds(feeds: List<Feed>) {
feeds.forEach { it.accountId = account.id }
database.newFeedDao().upsertFeeds(feeds, account)
}
private suspend fun insertFolders(folders: List<Folder>) {
folders.forEach { it.accountId = account.id }
database.newFolderDao().upsertFolders(folders, account)
}
private suspend fun insertItems(items: List<Item>) {
}
}

View File

@ -95,50 +95,70 @@ class TimelineScreenModel(
fun refreshTimeline() {
screenModelScope.launch(dispatcher) {
val selectedFeeds = if (currentAccount!!.isLocal) {
when (filters.value.subFilter) {
SubFilter.FEED -> listOf(
database.newFeedDao().selectFeed(filters.value.filterFeedId)
if (currentAccount!!.isLocal) {
refreshLocalAccount()
} else {
_timelineState.update { it.copy(isRefreshing = true) }
try {
repository?.synchronize()
} catch (e: Exception) {
// handle sync exceptions
}
_timelineState.update {
it.copy(
isRefreshing = false,
endSynchronizing = true
)
SubFilter.FOLDER -> database.newFeedDao()
.selectFeedsByFolder(filters.value.filterFolderId)
else -> listOf()
}
} else listOf()
_timelineState.update {
it.copy(
feedCount = 0,
feedMax = if (selectedFeeds.isNotEmpty())
selectedFeeds.size
else
database.newFeedDao().selectFeedCount(currentAccount!!.id)
)
}
}
}
_timelineState.update { it.copy(isRefreshing = true) }
val results = repository?.synchronize(
selectedFeeds = selectedFeeds,
onUpdate = { feed ->
_timelineState.update {
it.copy(
currentFeed = feed.name!!,
feedCount = it.feedCount + 1
)
}
}
private suspend fun refreshLocalAccount() {
val selectedFeeds = when (filters.value.subFilter) {
SubFilter.FEED -> listOf(
database.newFeedDao().selectFeed(filters.value.filterFeedId)
)
_timelineState.update {
it.copy(
isRefreshing = false,
endSynchronizing = true,
synchronizationErrors = if (results!!.second.isNotEmpty()) results.second else null
)
SubFilter.FOLDER -> database.newFeedDao()
.selectFeedsByFolder(filters.value.filterFolderId)
else -> listOf()
}
_timelineState.update {
it.copy(
feedCount = 0,
feedMax = if (selectedFeeds.isNotEmpty())
selectedFeeds.size
else
database.newFeedDao().selectFeedCount(currentAccount!!.id)
)
}
_timelineState.update { it.copy(isRefreshing = true) }
val results = repository?.synchronize(
selectedFeeds = selectedFeeds,
onUpdate = { feed ->
_timelineState.update {
it.copy(
currentFeed = feed.name!!,
feedCount = it.feedCount + 1
)
}
}
)
_timelineState.update {
it.copy(
isRefreshing = false,
endSynchronizing = true,
synchronizationErrors = if (results!!.second.isNotEmpty()) results.second else null
)
}
}

View File

@ -74,7 +74,7 @@ class NewFeedDaoTest {
/*Feed(
name = "Feed 1",
remoteId = "feed_1",
folderId = 1,
remoteFolderId = "folder_1",
accountId = account.id
),*/
@ -90,7 +90,7 @@ class NewFeedDaoTest {
Feed(
name = "Feed 3",
remoteId = "feed_3",
folderId = 1,
remoteFolderId = "folder_0",
accountId = account.id
),
)
@ -102,6 +102,6 @@ class NewFeedDaoTest {
assertTrue(allFeeds.any { it.remoteId == "feed_2" && it.folderId == 2 })
assertFalse(allFeeds.any { it.remoteId == "feed_1" })
assertTrue(allFeeds.any { it.remoteId == "feed_3" })
assertTrue(allFeeds.any { it.remoteId == "feed_3" && it.folderId == 1 })
}
}

View File

@ -64,16 +64,15 @@ abstract class NewFeedDao : NewBaseDao<Feed> {
val feedsToInsert = feeds.filter { feed -> localFeedIds.none { localFeedId -> feed.remoteId == localFeedId } }
val feedsToDelete = localFeedIds.filter { localFeedId -> feeds.none { feed -> localFeedId == feed.remoteId } }
// feeds to update
feeds.filter { feed -> localFeedIds.any { localFeedId -> feed.remoteId == localFeedId } }
.forEach { feed ->
val folderId: Int? = if (feed.remoteFolderId == null) {
feeds.forEach { feed ->
feed.folderId = if (feed.remoteFolderId == null) {
null
} else {
selectRemoteFolderLocalId(feed.remoteFolderId!!, account.id)
}
updateFeedNameAndFolder(feed.remoteId!!, account.id, feed.name!!, folderId)
// works only for already existing feeds
updateFeedNameAndFolder(feed.remoteId!!, account.id, feed.name!!, feed.folderId)
}
if (feedsToDelete.isNotEmpty()) {