Implement Nextcloud News add/update/delete feed actions

This commit is contained in:
Shinokuni 2024-06-16 21:43:37 +02:00
parent 4acaa9a85b
commit 07b6059921
12 changed files with 57 additions and 25 deletions

View File

@ -80,12 +80,12 @@ class NewNextcloudNewsDataSource(private val service: NewNextcloudNewsService) {
return service.createFeed(url, folderId) return service.createFeed(url, folderId)
} }
suspend fun changeFeedFolder(newFolderId: Int, feedId: Int) { suspend fun changeFeedFolder(newFolderId: Int?, feedId: Int) {
service.changeFeedFolder(feedId, mapOf("folderId" to newFolderId)) service.changeFeedFolder(feedId, mapOf("folderId" to newFolderId))
} }
suspend fun renameFeed(name: String, folderId: Int) { suspend fun renameFeed(name: String, feedId: Int) {
service.renameFeed(folderId, mapOf("feedTitle" to name)) service.renameFeed(feedId, mapOf("feedTitle" to name))
} }
suspend fun deleteFeed(feedId: Int) { suspend fun deleteFeed(feedId: Int) {

View File

@ -53,7 +53,7 @@ interface NewNextcloudNewsService {
suspend fun deleteFeed(@Path("feedId") feedId: Int) suspend fun deleteFeed(@Path("feedId") feedId: Int)
@PUT("feeds/{feedId}/move") @PUT("feeds/{feedId}/move")
suspend fun changeFeedFolder(@Path("feedId") feedId: Int, @Body folderIdMap: Map<String, Int>) suspend fun changeFeedFolder(@Path("feedId") feedId: Int, @Body folderIdMap: Map<String, Int?>)
@PUT("feeds/{feedId}/rename") @PUT("feeds/{feedId}/rename")
suspend fun renameFeed(@Path("feedId") feedId: Int, @Body feedTitleMap: Map<String, String>) suspend fun renameFeed(@Path("feedId") feedId: Int, @Body feedTitleMap: Map<String, String>)

View File

@ -88,7 +88,7 @@ public class EditFeedDialogFragment extends DialogFragment implements AdapterVie
viewModel.getFolders().observe(this, folders -> { viewModel.getFolders().observe(this, folders -> {
values = new TreeMap<>(String::compareTo); values = new TreeMap<>(String::compareTo);
if (!account.getAccountType().getAccountConfig().isNoFolderCase()) if (!account.getAccountType().getAccountConfig().getAddNoFolder())
values.put(getString(R.string.no_folder), 0); values.put(getString(R.string.no_folder), 0);
for (Folder folder : folders) { for (Folder folder : folders) {

View File

@ -54,7 +54,6 @@ class FeedScreenModel(
_updateFeedDialogState.update { _updateFeedDialogState.update {
it.copy( it.copy(
isFeedUrlReadOnly = account.config.isFeedUrlReadOnly, isFeedUrlReadOnly = account.config.isFeedUrlReadOnly,
isNoFolderCase = account.config.isNoFolderCase
) )
} }
@ -91,7 +90,6 @@ class FeedScreenModel(
_updateFeedDialogState.update { _updateFeedDialogState.update {
it.copy( it.copy(
isFeedUrlReadOnly = account.config.isFeedUrlReadOnly, isFeedUrlReadOnly = account.config.isFeedUrlReadOnly,
isNoFolderCase = account.config.isNoFolderCase
) )
} }
@ -101,7 +99,7 @@ class FeedScreenModel(
.collect { folders -> .collect { folders ->
_updateFeedDialogState.update { _updateFeedDialogState.update {
it.copy( it.copy(
folders = if (!it.isNoFolderCase) { // TODO implement no folder case properly folders = if (currentAccount!!.config.addNoFolder) {
folders + listOf( folders + listOf(
Folder( Folder(
id = 0, id = 0,
@ -156,7 +154,8 @@ class FeedScreenModel(
feedId = state.feed.id, feedId = state.feed.id,
feedName = state.feed.name!!, feedName = state.feed.name!!,
feedUrl = state.feed.url!!, feedUrl = state.feed.url!!,
selectedFolder = state.folder selectedFolder = state.folder ?: it.folders.find { folder -> folder.id == 0 },
feedRemoteId = state.feed.remoteId
) )
} }
} }
@ -336,8 +335,11 @@ class FeedScreenModel(
id = feedId, id = feedId,
name = feedName, name = feedName,
url = feedUrl, url = feedUrl,
folderId = selectedFolder?.id, folderId = if (selectedFolder?.id != 0)
remoteFolderId = selectedFolder?.remoteId selectedFolder?.id
else null,
remoteFolderId = selectedFolder?.remoteId,
remoteId = feedRemoteId
) )
) )
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -41,6 +41,7 @@ data class AddFeedDialogState(
data class UpdateFeedDialogState( data class UpdateFeedDialogState(
val feedId: Int = 0, val feedId: Int = 0,
val feedRemoteId: String? = null,
val feedName: String = "", val feedName: String = "",
val feedNameError: TextFieldError? = null, val feedNameError: TextFieldError? = null,
val feedUrl: String = "", val feedUrl: String = "",
@ -49,7 +50,6 @@ data class UpdateFeedDialogState(
val folders: List<Folder> = listOf(), val folders: List<Folder> = listOf(),
val isAccountDropDownExpanded: Boolean = false, val isAccountDropDownExpanded: Boolean = false,
val isFeedUrlReadOnly: Boolean = true, val isFeedUrlReadOnly: Boolean = true,
val isNoFolderCase: Boolean = false,
val exception: Exception? = null val exception: Exception? = null
) { ) {
val isFeedNameError val isFeedNameError

View File

@ -40,6 +40,7 @@ class GetFoldersWithFeeds(
url = it.feedUrl, url = it.feedUrl,
siteUrl = it.feedSiteUrl, siteUrl = it.feedSiteUrl,
description = it.feedDescription, description = it.feedDescription,
remoteId = it.feedRemoteId,
unreadCount = itemCounts[it.feedId] ?: 0 unreadCount = itemCounts[it.feedId] ?: 0
) )
} }

View File

@ -80,7 +80,35 @@ class NextcloudNewsRepository(
newFeeds: List<Feed>, newFeeds: List<Feed>,
onUpdate: (Feed) -> Unit onUpdate: (Feed) -> Unit
): ErrorResult { ): ErrorResult {
TODO("Not yet implemented") val errors = mutableMapOf<Feed, Exception>()
for (newFeed in newFeeds) {
onUpdate(newFeed)
try {
val feeds = dataSource.createFeed(newFeed.url!!, null)
insertFeeds(feeds)
} catch (e: Exception) {
errors[newFeed] = e
}
}
return errors
}
override suspend fun updateFeed(feed: Feed) {
val folder =
if (feed.folderId != null) database.newFolderDao().select(feed.folderId!!) else null
dataSource.renameFeed(feed.name!!, feed.remoteId!!.toInt())
dataSource.changeFeedFolder(folder?.remoteId?.toInt(), feed.remoteId!!.toInt())
super.updateFeed(feed)
}
override suspend fun deleteFeed(feed: Feed) {
dataSource.deleteFeed(feed.remoteId!!.toInt())
super.deleteFeed(feed)
} }
private suspend fun insertFolders(folders: List<Folder>) { private suspend fun insertFolders(folders: List<Folder>) {

View File

@ -164,6 +164,6 @@
<string name="http_error_4XX">Erreur HTTP %1$d, veuillez vérifier vos champs</string> <string name="http_error_4XX">Erreur HTTP %1$d, veuillez vérifier vos champs</string>
<string name="http_error_5XX">Erreur HTTP %1$d, erreur serveur</string> <string name="http_error_5XX">Erreur HTTP %1$d, erreur serveur</string>
<string name="http_error">Erreur HTTP %1$d</string> <string name="http_error">Erreur HTTP %1$d</string>
<string name="feed_url_read_only">L\'API de FreshRSS ne permet pas de modifier l\'URL</string> <string name="feed_url_read_only">L\'API ne permet pas de modifier l\'URL</string>
<string name="updating_account">Mise à jour du compte %1$s</string> <string name="updating_account">Mise à jour du compte %1$s</string>
</resources> </resources>

View File

@ -170,6 +170,6 @@
<string name="http_error_4XX">HTTP error %1$d, please check your fields</string> <string name="http_error_4XX">HTTP error %1$d, please check your fields</string>
<string name="http_error_5XX">HTTP error %1$d, server error</string> <string name="http_error_5XX">HTTP error %1$d, server error</string>
<string name="http_error">HTTP error %1$d</string> <string name="http_error">HTTP error %1$d</string>
<string name="feed_url_read_only">FreshRSS API doesn\'t support Feed URL modification</string> <string name="feed_url_read_only">The API doesn\'t support Feed URL modification</string>
<string name="updating_account">Updating %1$s account</string> <string name="updating_account">Updating %1$s account</string>
</resources> </resources>

View File

@ -13,13 +13,13 @@ interface NewFolderDao : NewBaseDao<Folder> {
@Query(""" @Query("""
Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl, Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl,
Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Folder.id As folderId, Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Feed.remoteId as feedRemoteId, Folder.id As folderId,
Folder.name As folderName, Feed.account_id as accountId, Folder.remoteId as folderRemoteId Folder.name As folderName, Feed.account_id as accountId, Folder.remoteId as folderRemoteId
From Feed Left Join Folder On Folder.id = Feed.folder_id From Feed Left Join Folder On Folder.id = Feed.folder_id
Where Feed.folder_id is NULL OR Feed.folder_id is NOT NULL And Feed.id is NULL Or Feed.id is NOT NULL And Feed.account_id = :accountId Group By Feed.id Where Feed.folder_id is NULL OR Feed.folder_id is NOT NULL And Feed.id is NULL Or Feed.id is NOT NULL And Feed.account_id = :accountId Group By Feed.id
UNION ALL UNION ALL
Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl, Select Feed.id As feedId, Feed.name As feedName, Feed.icon_url As feedIcon, Feed.url As feedUrl,
Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription,Folder.id As folderId, Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Feed.remoteId as feedRemoteId, Folder.id As folderId,
Folder.name As folderName, Folder.account_id as accountId, Folder.remoteId as folderRemoteId Folder.name As folderName, Folder.account_id as accountId, Folder.remoteId as folderRemoteId
From Folder Left Join Feed On Folder.id = Feed.folder_id From Folder Left Join Feed On Folder.id = Feed.folder_id
Where Feed.id is NULL And Folder.account_id = :accountId Where Feed.id is NULL And Folder.account_id = :accountId
@ -29,6 +29,9 @@ interface NewFolderDao : NewBaseDao<Folder> {
@Query("Select * From Folder Where account_id = :accountId") @Query("Select * From Folder Where account_id = :accountId")
fun selectFolders(accountId: Int): Flow<List<Folder>> fun selectFolders(accountId: Int): Flow<List<Folder>>
@Query("Select * from Folder Where id = :folderId")
fun select(folderId: Int): Folder
@Query("Select * From Folder Where name = :name And account_id = :accountId") @Query("Select * From Folder Where name = :name And account_id = :accountId")
suspend fun selectFolderByName(name: String, accountId: Int): Folder? suspend fun selectFolderByName(name: String, accountId: Int): Folder?

View File

@ -7,32 +7,29 @@ import kotlinx.parcelize.Parcelize
data class AccountConfig( data class AccountConfig(
val isFeedUrlReadOnly: Boolean, // Enable or disable feed url modification in Feed Tab val isFeedUrlReadOnly: Boolean, // Enable or disable feed url modification in Feed Tab
val canCreateFolder: Boolean, // Enable or disable folder creation in Feed Tab val canCreateFolder: Boolean, // Enable or disable folder creation in Feed Tab
val isNoFolderCase: Boolean, // Add a "No folder" option when modifying a feed's folder TODO add better name val addNoFolder: Boolean, // Add a "No folder" option when modifying a feed's folder
val useSeparateState: Boolean, // Let know if it uses ItemState table to synchronize read/star state val useSeparateState: Boolean, // Let know if it uses ItemState table to synchronize read/star state
) : Parcelable { ) : Parcelable {
companion object { companion object {
@JvmField
val LOCAL = AccountConfig( val LOCAL = AccountConfig(
isFeedUrlReadOnly = false, isFeedUrlReadOnly = false,
canCreateFolder = true, canCreateFolder = true,
isNoFolderCase = false, addNoFolder = true,
useSeparateState = false, useSeparateState = false,
) )
@JvmField
val NEXTCLOUD_NEWS = AccountConfig( val NEXTCLOUD_NEWS = AccountConfig(
isFeedUrlReadOnly = false, isFeedUrlReadOnly = true,
canCreateFolder = true, canCreateFolder = true,
isNoFolderCase = false, addNoFolder = true,
useSeparateState = false, useSeparateState = false,
) )
@JvmField
val FRESHRSS = AccountConfig( val FRESHRSS = AccountConfig(
isFeedUrlReadOnly = true, isFeedUrlReadOnly = true,
canCreateFolder = false, canCreateFolder = false,
isNoFolderCase = true, addNoFolder = false,
useSeparateState = true, useSeparateState = true,
) )
} }

View File

@ -22,6 +22,7 @@ data class FolderWithFeed(
val feedUrl: String? = null, val feedUrl: String? = null,
val feedDescription: String? = null, val feedDescription: String? = null,
val feedSiteUrl: String? = null, val feedSiteUrl: String? = null,
val feedRemoteId: String? = null,
val accountId: Int = 0 val accountId: Int = 0
) )