Implement FreshRSS update/delete folder

This commit is contained in:
Shinokuni 2024-05-19 23:31:36 +02:00
parent 064d588b28
commit 219d816483
8 changed files with 76 additions and 19 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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<FeedScreenModel>()
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

View File

@ -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(

View File

@ -85,8 +85,18 @@ class FreshRSSRepository(
override suspend fun insertNewFeeds(
newFeeds: List<Feed>,
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<Feed>) {

View File

@ -25,6 +25,7 @@ class GetFoldersWithFeeds(
Folder(
id = it.folderId!!,
name = it.folderName,
remoteId = it.folderRemoteId,
accountId = it.accountId
)
} else {

View File

@ -13,14 +13,14 @@ interface NewFolderDao : NewBaseDao<Folder> {
@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
""")

View File

@ -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,