diff --git a/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSDataSource.java b/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSDataSource.java index be17ec01..aec11cb9 100644 --- a/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSDataSource.java +++ b/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSDataSource.java @@ -273,17 +273,17 @@ public class FreshRSSDataSource { */ private Completable setItemsReadState(@NonNull FreshRSSSyncData syncData, @NonNull String token) { Completable readItemsCompletable; - if (syncData.getReadItemsIds().isEmpty()) { + if (syncData.getReadIds().isEmpty()) { readItemsCompletable = Completable.complete(); } else { - readItemsCompletable = setItemsReadState(true, syncData.getReadItemsIds(), token); + readItemsCompletable = setItemsReadState(true, syncData.getReadIds(), token); } Completable unreadItemsCompletable; - if (syncData.getUnreadItemsIds().isEmpty()) { + if (syncData.getUnreadIds().isEmpty()) { unreadItemsCompletable = Completable.complete(); } else { - unreadItemsCompletable = setItemsReadState(false, syncData.getUnreadItemsIds(), token); + unreadItemsCompletable = setItemsReadState(false, syncData.getUnreadIds(), token); } return readItemsCompletable.concatWith(unreadItemsCompletable); @@ -298,17 +298,17 @@ public class FreshRSSDataSource { */ private Completable setItemsStarState(@NonNull FreshRSSSyncData syncData, @NonNull String token) { Completable starredItemsCompletable; - if (syncData.getStarredItemsIds().isEmpty()) { + if (syncData.getStarredIds().isEmpty()) { starredItemsCompletable = Completable.complete(); } else { - starredItemsCompletable = setItemsStarState(true, syncData.getStarredItemsIds(), token); + starredItemsCompletable = setItemsStarState(true, syncData.getStarredIds(), token); } Completable unstarredItemsCompletable; - if (syncData.getUnstarredItemsIds().isEmpty()) { + if (syncData.getUnstarredIds().isEmpty()) { unstarredItemsCompletable = Completable.complete(); } else { - unstarredItemsCompletable = setItemsStarState(false, syncData.getUnstarredItemsIds(), token); + unstarredItemsCompletable = setItemsStarState(false, syncData.getUnstarredIds(), token); } return starredItemsCompletable.concatWith(unstarredItemsCompletable); diff --git a/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSSyncData.kt b/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSSyncData.kt index bc06b778..80ba5ce7 100644 --- a/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSSyncData.kt +++ b/api/src/main/java/com/readrops/api/services/freshrss/FreshRSSSyncData.kt @@ -2,8 +2,8 @@ package com.readrops.api.services.freshrss data class FreshRSSSyncData( var lastModified: Long = 0, - var readItemsIds: List = listOf(), - var unreadItemsIds: List = listOf(), - var starredItemsIds: List = listOf(), - var unstarredItemsIds: List = listOf(), + var readIds: List = listOf(), + var unreadIds: List = listOf(), + var starredIds: List = listOf(), + var unstarredIds: List = listOf(), ) \ No newline at end of file diff --git a/api/src/main/java/com/readrops/api/services/freshrss/NewFreshRSSDataSource.kt b/api/src/main/java/com/readrops/api/services/freshrss/NewFreshRSSDataSource.kt index 0e2b335a..9f1e2b0e 100644 --- a/api/src/main/java/com/readrops/api/services/freshrss/NewFreshRSSDataSource.kt +++ b/api/src/main/java/com/readrops/api/services/freshrss/NewFreshRSSDataSource.kt @@ -121,22 +121,22 @@ class NewFreshRSSDataSource(private val service: NewFreshRSSService) { } private suspend fun setItemsReadState(syncData: FreshRSSSyncData, token: String) { - if (syncData.readItemsIds.isNotEmpty()) { - setItemsReadState(true, syncData.readItemsIds, token) + if (syncData.readIds.isNotEmpty()) { + setItemsReadState(true, syncData.readIds, token) } - if (syncData.unreadItemsIds.isNotEmpty()) { - setItemsReadState(false, syncData.unreadItemsIds, token) + if (syncData.unreadIds.isNotEmpty()) { + setItemsReadState(false, syncData.unreadIds, token) } } private suspend fun setItemsStarState(syncData: FreshRSSSyncData, token: String) { - if (syncData.starredItemsIds.isNotEmpty()) { - setItemStarState(true, syncData.starredItemsIds, token) + if (syncData.starredIds.isNotEmpty()) { + setItemStarState(true, syncData.starredIds, token) } - if (syncData.unstarredItemsIds.isNotEmpty()) { - setItemStarState(false, syncData.unstarredItemsIds, token) + if (syncData.unstarredIds.isNotEmpty()) { + setItemStarState(false, syncData.unstarredIds, token) } } diff --git a/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java index 880513b1..945554c1 100644 --- a/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java +++ b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java @@ -96,22 +96,22 @@ public class FreshRSSRepository extends ARepository { .itemStateChangesDao() .getItemStateChanges(account.getId()); - syncData.setReadItemsIds(itemStateChanges.stream() + syncData.setReadIds(itemStateChanges.stream() .filter(it -> it.getReadChange() && it.getRead()) .map(ItemReadStarState::getRemoteId) .collect(Collectors.toList())); - syncData.setUnreadItemsIds(itemStateChanges.stream() + syncData.setUnreadIds(itemStateChanges.stream() .filter(it -> it.getReadChange() && !it.getRead()) .map(ItemReadStarState::getRemoteId) .collect(Collectors.toList())); - syncData.setStarredItemsIds(itemStateChanges.stream() + syncData.setStarredIds(itemStateChanges.stream() .filter(it -> it.getStarChange() && it.getStarred()) .map(ItemReadStarState::getRemoteId) .collect(Collectors.toList())); - syncData.setUnstarredItemsIds(itemStateChanges.stream() + syncData.setUnstarredIds(itemStateChanges.stream() .filter(it -> it.getStarChange() && !it.getStarred()) .map(ItemReadStarState::getRemoteId) .collect(Collectors.toList())); diff --git a/appcompose/src/main/java/com/readrops/app/compose/repositories/FreshRSSRepository.kt b/appcompose/src/main/java/com/readrops/app/compose/repositories/FreshRSSRepository.kt index ccd6a775..c956d2b5 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/repositories/FreshRSSRepository.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/repositories/FreshRSSRepository.kt @@ -42,7 +42,19 @@ class FreshRSSRepository( ): Pair = throw NotImplementedError("This method can't be called here") override suspend fun synchronize(): SyncResult { - val syncData = FreshRSSSyncData() + val itemStateChanges = database.newItemStateChangeDao() + .selectItemStateChanges(account.id) + + val syncData = FreshRSSSyncData( + readIds = itemStateChanges.filter { it.readChange && it.read } + .map { it.remoteId }, + unreadIds = itemStateChanges.filter { it.readChange && !it.read } + .map { it.remoteId }, + starredIds = itemStateChanges.filter { it.starChange && it.starred } + .map { it.remoteId }, + unstarredIds = itemStateChanges.filter { it.starChange && !it.starred } + .map { it.remoteId } + ) val syncType: SyncType if (account.lastModified != 0L) { @@ -65,6 +77,8 @@ class FreshRSSRepository( account.lastModified = newLastModified database.newAccountDao().updateLastModified(newLastModified, account.id) + + database.newItemStateChangeDao().resetStateChanges(account.id) } } diff --git a/appcompose/src/main/java/com/readrops/app/compose/repositories/ARepository.kt b/appcompose/src/main/java/com/readrops/app/compose/repositories/Repository.kt similarity index 60% rename from appcompose/src/main/java/com/readrops/app/compose/repositories/ARepository.kt rename to appcompose/src/main/java/com/readrops/app/compose/repositories/Repository.kt index 17ab69a6..9082cbe0 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/repositories/ARepository.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/repositories/Repository.kt @@ -5,28 +5,26 @@ 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.ItemState import com.readrops.db.entities.account.Account typealias ErrorResult = Map -abstract class ARepository( - val database: Database, - val account: Account -) { +interface Repository { /** * This method is intended for remote accounts. */ - abstract suspend fun login(account: Account) + suspend fun login(account: Account) /** * Global synchronization for the local account. - * @param selectedFeeds feeds to be updated - * @param onUpdate get synchronization status - * @return returns the result of the synchronization used by notifications + * @param selectedFeeds feeds to be updated, will fetch all account feeds if list is empty + * @param onUpdate notify each feed update + * @return the result of the synchronization used by notifications * and errors per feed if occurred to be transmitted to the user */ - abstract suspend fun synchronize( + suspend fun synchronize( selectedFeeds: List, onUpdate: (Feed) -> Unit ): Pair @@ -34,16 +32,23 @@ abstract class ARepository( /** * Global synchronization for remote accounts. Unlike the local account, remote accounts * won't benefit from synchronization status and granular synchronization + * @return the result of the synchronization */ - abstract suspend fun synchronize(): SyncResult + suspend fun synchronize(): SyncResult - abstract suspend fun insertNewFeeds(newFeeds: List, onUpdate: (Feed) -> Unit): ErrorResult + /** + * Insert new feeds by notifying each of them + * @param newFeeds feeds to insert + * @param onUpdate notify each feed insertion + * @return errors by feed + */ + suspend fun insertNewFeeds(newFeeds: List, onUpdate: (Feed) -> Unit): ErrorResult } abstract class BaseRepository( - database: Database, - account: Account, -) : ARepository(database, account) { + val database: Database, + val account: Account, +) : Repository { open suspend fun updateFeed(feed: Feed) = database.newFeedDao().updateFeedFields(feed.id, feed.name!!, feed.url!!, feed.folderId) @@ -57,11 +62,39 @@ abstract class BaseRepository( open suspend fun deleteFolder(folder: Folder) = database.newFolderDao().delete(folder) open suspend fun setItemReadState(item: Item) { - database.newItemDao().updateReadState(item.id, item.isRead) + // TODO handle Nextcloud News case + if (account.config.useSeparateState) { + database.newItemStateChangeDao().upsertItemReadStateChange(item, account.id, true) + database.newItemStateDao().upsertItemReadState( + ItemState( + id = 0, + read = item.isRead, + starred = item.isStarred, + remoteId = item.remoteId!!, + accountId = account.id + ) + ) + } else { + database.newItemDao().updateReadState(item.id, item.isRead) + } } open suspend fun setItemStarState(item: Item) { - database.newItemDao().updateStarState(item.id, item.isStarred) + // TODO handle Nextcloud News case + if (account.config.useSeparateState) { + database.newItemStateChangeDao().upsertItemStarStateChange(item, account.id, true) + database.newItemStateDao().upsertItemStarState( + ItemState( + id = 0, + read = item.isRead, + starred = item.isStarred, + remoteId = item.remoteId!!, + accountId = account.id + ) + ) + } else { + database.newItemDao().updateStarState(item.id, item.isStarred) + } } open suspend fun setAllItemsRead(accountId: Int) { diff --git a/db/src/main/java/com/readrops/db/dao/newdao/NewItemStateChangeDao.kt b/db/src/main/java/com/readrops/db/dao/newdao/NewItemStateChangeDao.kt index cf94bb26..168943bb 100644 --- a/db/src/main/java/com/readrops/db/dao/newdao/NewItemStateChangeDao.kt +++ b/db/src/main/java/com/readrops/db/dao/newdao/NewItemStateChangeDao.kt @@ -17,13 +17,13 @@ interface NewItemStateChangeDao: NewBaseDao { "ItemStateChange.read_change, ItemStateChange.star_change, Item.remoteId " + "From ItemStateChange Inner Join Item On ItemStateChange.id = Item.id " + "Left Join ItemState On ItemState.remote_id = Item.remoteId Where ItemStateChange.account_id = :accountId") - suspend fun getItemStateChanges(accountId: Int): List + suspend fun selectItemStateChanges(accountId: Int): List @Query("Select Item.read, Item.starred," + "ItemStateChange.read_change, ItemStateChange.star_change, Item.remoteId " + "From ItemStateChange Inner Join Item On ItemStateChange.id = Item.id " + "Where ItemStateChange.account_id = :accountId") - suspend fun getNextcloudNewsStateChanges(accountId: Int): List + suspend fun selectNextcloudNewsStateChanges(accountId: Int): List @Query("Select Case When :itemId In (Select id From ItemStateChange Where read_change = 1) Then 1 Else 0 End") suspend fun readStateChangeExists(itemId: Int): Boolean @@ -34,9 +34,9 @@ interface NewItemStateChangeDao: NewBaseDao { suspend fun upsertItemReadStateChange(item: Item, accountId: Int, useSeparateState: Boolean) { if (itemStateChangeExists(item.id, accountId)) { val oldItemReadState = if (useSeparateState) - getItemReadState(item.remoteId!!, accountId) + selectItemReadState(item.remoteId!!, accountId) else - getStandardItemReadState(item.remoteId!!, accountId) + selectStandardItemReadState(item.remoteId!!, accountId) val readChange = item.isRead != oldItemReadState @@ -58,9 +58,9 @@ interface NewItemStateChangeDao: NewBaseDao { suspend fun upsertItemStarStateChange(item: Item, accountId: Int, useSeparateState: Boolean) { if (itemStateChangeExists(item.id, accountId)) { val oldItemStarState = if (useSeparateState) - getItemStarState(item.remoteId!!, accountId) + selectItemStarState(item.remoteId!!, accountId) else - getStandardItemStarState(item.remoteId!!, accountId) + selectStandardItemStarState(item.remoteId!!, accountId) val starChange = item.isStarred != oldItemStarState @@ -86,16 +86,16 @@ interface NewItemStateChangeDao: NewBaseDao { fun itemStateChangeExists(id: Int, accountId: Int): Boolean @Query("Select read From ItemState Where remote_id = :remoteId And account_id = :accountId") - fun getItemReadState(remoteId: String, accountId: Int): Boolean + fun selectItemReadState(remoteId: String, accountId: Int): Boolean @Query("Select read From Item Inner Join Feed On Item.feed_id = Feed.id Where Item.remoteId = :remoteId And account_id = :accountId") - fun getStandardItemReadState(remoteId: String, accountId: Int): Boolean + fun selectStandardItemReadState(remoteId: String, accountId: Int): Boolean @Query("Select starred From ItemState Where remote_id = :remoteId And account_id = :accountId") - fun getItemStarState(remoteId: String, accountId: Int): Boolean + fun selectItemStarState(remoteId: String, accountId: Int): Boolean @Query("Select starred From Item Inner Join Feed On Item.feed_id = Feed.id Where Item.remoteId = :remoteId And account_id = :accountId") - fun getStandardItemStarState(remoteId: String, accountId: Int): Boolean + fun selectStandardItemStarState(remoteId: String, accountId: Int): Boolean @Query("Update ItemStateChange set read_change = :readChange Where id = :id") fun updateItemReadStateChange(readChange: Boolean, id: Int)