From 219d816483f2b0631e59919748eb4b291ff5abe5 Mon Sep 17 00:00:00 2001 From: Shinokuni Date: Sun, 19 May 2024 23:31:36 +0200 Subject: [PATCH] Implement FreshRSS update/delete folder --- .../app/compose/feeds/FeedScreenModel.kt | 33 ++++++++++++++----- .../readrops/app/compose/feeds/FeedState.kt | 6 ++-- .../com/readrops/app/compose/feeds/FeedTab.kt | 20 +++++++++-- .../app/compose/feeds/dialogs/FolderDialog.kt | 12 ++++++- .../repositories/FreshRSSRepository.kt | 14 ++++++-- .../repositories/GetFoldersWithFeeds.kt | 1 + .../readrops/db/dao/newdao/NewFolderDao.kt | 8 ++--- .../com/readrops/db/pojo/FeedWithFolder.kt | 1 + 8 files changed, 76 insertions(+), 19 deletions(-) diff --git a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedScreenModel.kt b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedScreenModel.kt index 47890197..97bd499e 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedScreenModel.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedScreenModel.kt @@ -102,7 +102,12 @@ class FeedScreenModel( _updateFeedDialogState.update { it.copy( folders = if (!it.isNoFolderCase) { // TODO implement no folder case properly - folders + listOf(Folder(id = 0, name = context.resources.getString(R.string.no_folder))) + folders + listOf( + Folder( + id = 0, + name = context.resources.getString(R.string.no_folder) + ) + ) } else { folders } @@ -128,6 +133,7 @@ class FeedScreenModel( it.copy( folder = Folder(), nameError = null, + exception = null ) } } @@ -166,7 +172,11 @@ class FeedScreenModel( fun deleteFolder(folder: Folder) { screenModelScope.launch(Dispatchers.IO) { - repository?.deleteFolder(folder) + try { + repository?.deleteFolder(folder) + } catch (e: Exception) { + _feedState.update { it.copy(exception = e) } + } } } @@ -340,17 +350,24 @@ class FeedScreenModel( } screenModelScope.launch(Dispatchers.IO) { - if (updateFolder) { - repository?.updateFolder(_folderState.value.folder) - } else { - repository?.addFolder(_folderState.value.folder.apply { - accountId = currentAccount!!.id - }) + try { + if (updateFolder) { + repository?.updateFolder(_folderState.value.folder) + } else { + repository?.addFolder(_folderState.value.folder.apply { + accountId = currentAccount!!.id + }) + } + } catch (e: Exception) { + _folderState.update { it.copy(exception = e) } + return@launch } closeDialog(DialogState.AddFolder) } } + fun resetException() = _feedState.update { it.copy(exception = null) } + // add/update folder } \ No newline at end of file diff --git a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedState.kt b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedState.kt index 68062224..672dca11 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedState.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedState.kt @@ -9,7 +9,8 @@ data class FeedState( val foldersAndFeeds: FolderAndFeedsState = FolderAndFeedsState.InitialState, val dialog: DialogState? = null, val areFoldersExpanded: Boolean = false, - val displayFolderCreationButton: Boolean = false + val displayFolderCreationButton: Boolean = false, + val exception: Exception? = null ) sealed interface DialogState { @@ -61,8 +62,9 @@ data class UpdateFeedDialogState( data class FolderState( val folder: Folder = Folder(), val nameError: TextFieldError? = null, + val exception: Exception? = null ) { val name = folder.name - val isError = nameError != null + val isTextFieldError = nameError != null } \ No newline at end of file diff --git a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedTab.kt b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedTab.kt index 03f292ca..fe248289 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedTab.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/feeds/FeedTab.kt @@ -17,13 +17,18 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SmallFloatingActionButton +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource @@ -38,6 +43,7 @@ import com.readrops.app.compose.feeds.dialogs.AddFeedDialog import com.readrops.app.compose.feeds.dialogs.FeedModalBottomSheet import com.readrops.app.compose.feeds.dialogs.FolderDialog import com.readrops.app.compose.feeds.dialogs.UpdateFeedDialog +import com.readrops.app.compose.util.ErrorMessage import com.readrops.app.compose.util.components.CenteredProgressIndicator import com.readrops.app.compose.util.components.ErrorMessage import com.readrops.app.compose.util.components.Placeholder @@ -59,11 +65,20 @@ object FeedTab : Tab { override fun Content() { val haptic = LocalHapticFeedback.current val uriHandler = LocalUriHandler.current + val context = LocalContext.current val viewModel = getScreenModel() - val state by viewModel.feedsState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(state.exception) { + if (state.exception != null) { + snackbarHostState.showSnackbar(ErrorMessage.get(state.exception!!, context)) + viewModel.resetException() + } + } + when (val dialog = state.dialog) { is DialogState.AddFeed -> { AddFeedDialog( @@ -204,7 +219,8 @@ object FeedTab : Tab { ) } } - } + }, + snackbarHost = { SnackbarHost(snackbarHostState) } ) { paddingValues -> Box( modifier = Modifier diff --git a/appcompose/src/main/java/com/readrops/app/compose/feeds/dialogs/FolderDialog.kt b/appcompose/src/main/java/com/readrops/app/compose/feeds/dialogs/FolderDialog.kt index 83be971d..c4b26d8b 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/feeds/dialogs/FolderDialog.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/feeds/dialogs/FolderDialog.kt @@ -4,16 +4,19 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.readrops.app.compose.R import com.readrops.app.compose.feeds.FeedScreenModel +import com.readrops.app.compose.util.ErrorMessage import com.readrops.app.compose.util.components.BaseDialog import com.readrops.app.compose.util.theme.LargeSpacer @@ -50,10 +53,17 @@ fun FolderDialog( } } }, - isError = state.isError, + isError = state.isTextFieldError, supportingText = { Text(text = state.nameError?.errorText().orEmpty()) } ) + if (state.exception != null) { + Text( + text = ErrorMessage.get(state.exception!!, LocalContext.current), + color = MaterialTheme.colorScheme.error + ) + } + LargeSpacer() TextButton( 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 c956d2b5..6ab26d8c 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 @@ -85,8 +85,18 @@ class FreshRSSRepository( override suspend fun insertNewFeeds( newFeeds: List, onUpdate: (Feed) -> Unit - ): ErrorResult { - TODO("Not yet implemented") + ): ErrorResult = TODO("Not yet implemented") + + override suspend fun updateFolder(folder: Folder) { + dataSource.updateFolder(account.writeToken!!, folder.remoteId!!, folder.name!!) + folder.remoteId = NewFreshRSSDataSource.FOLDER_PREFIX + folder.name + + super.updateFolder(folder) + } + + override suspend fun deleteFolder(folder: Folder) { + dataSource.deleteFolder(account.writeToken!!, folder.remoteId!!) + super.deleteFolder(folder) } private suspend fun insertFeeds(feeds: List) { 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 index 86a1cf77..6a13a8e3 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/repositories/GetFoldersWithFeeds.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/repositories/GetFoldersWithFeeds.kt @@ -25,6 +25,7 @@ class GetFoldersWithFeeds( Folder( id = it.folderId!!, name = it.folderName, + remoteId = it.folderRemoteId, accountId = it.accountId ) } else { 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 index f21122c7..06cc5aa3 100644 --- a/db/src/main/java/com/readrops/db/dao/newdao/NewFolderDao.kt +++ b/db/src/main/java/com/readrops/db/dao/newdao/NewFolderDao.kt @@ -13,14 +13,14 @@ interface NewFolderDao : NewBaseDao { @Query(""" 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, Folder.name As folderName, Feed.account_id as accountId + Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Folder.id As folderId, + Folder.name As folderName, Feed.account_id as accountId, Folder.remoteId as folderRemoteId 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 UNION ALL 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, Folder.name As folderName, Folder.account_id as accountId + Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription,Folder.id As folderId, + Folder.name As folderName, Folder.account_id as accountId, Folder.remoteId as folderRemoteId From Folder Left Join Feed On Folder.id = Feed.folder_id Where Feed.id is NULL And Folder.account_id = :accountId """) diff --git a/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt b/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt index 067f13be..a6bb950d 100644 --- a/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt +++ b/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt @@ -15,6 +15,7 @@ data class FeedWithFolder( data class FolderWithFeed( val folderId: Int?, val folderName: String?, + val folderRemoteId: String?, val feedId: Int = 0, val feedName: String? = null, val feedIcon: String? = null,