Implement FreshRSS update/delete folder
This commit is contained in:
parent
064d588b28
commit
219d816483
@ -102,7 +102,12 @@ class FeedScreenModel(
|
|||||||
_updateFeedDialogState.update {
|
_updateFeedDialogState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
folders = if (!it.isNoFolderCase) { // TODO implement no folder case properly
|
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 {
|
} else {
|
||||||
folders
|
folders
|
||||||
}
|
}
|
||||||
@ -128,6 +133,7 @@ class FeedScreenModel(
|
|||||||
it.copy(
|
it.copy(
|
||||||
folder = Folder(),
|
folder = Folder(),
|
||||||
nameError = null,
|
nameError = null,
|
||||||
|
exception = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +172,11 @@ class FeedScreenModel(
|
|||||||
|
|
||||||
fun deleteFolder(folder: Folder) {
|
fun deleteFolder(folder: Folder) {
|
||||||
screenModelScope.launch(Dispatchers.IO) {
|
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) {
|
screenModelScope.launch(Dispatchers.IO) {
|
||||||
if (updateFolder) {
|
try {
|
||||||
repository?.updateFolder(_folderState.value.folder)
|
if (updateFolder) {
|
||||||
} else {
|
repository?.updateFolder(_folderState.value.folder)
|
||||||
repository?.addFolder(_folderState.value.folder.apply {
|
} else {
|
||||||
accountId = currentAccount!!.id
|
repository?.addFolder(_folderState.value.folder.apply {
|
||||||
})
|
accountId = currentAccount!!.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
_folderState.update { it.copy(exception = e) }
|
||||||
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog(DialogState.AddFolder)
|
closeDialog(DialogState.AddFolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resetException() = _feedState.update { it.copy(exception = null) }
|
||||||
|
|
||||||
// add/update folder
|
// add/update folder
|
||||||
}
|
}
|
@ -9,7 +9,8 @@ data class FeedState(
|
|||||||
val foldersAndFeeds: FolderAndFeedsState = FolderAndFeedsState.InitialState,
|
val foldersAndFeeds: FolderAndFeedsState = FolderAndFeedsState.InitialState,
|
||||||
val dialog: DialogState? = null,
|
val dialog: DialogState? = null,
|
||||||
val areFoldersExpanded: Boolean = false,
|
val areFoldersExpanded: Boolean = false,
|
||||||
val displayFolderCreationButton: Boolean = false
|
val displayFolderCreationButton: Boolean = false,
|
||||||
|
val exception: Exception? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface DialogState {
|
sealed interface DialogState {
|
||||||
@ -61,8 +62,9 @@ data class UpdateFeedDialogState(
|
|||||||
data class FolderState(
|
data class FolderState(
|
||||||
val folder: Folder = Folder(),
|
val folder: Folder = Folder(),
|
||||||
val nameError: TextFieldError? = null,
|
val nameError: TextFieldError? = null,
|
||||||
|
val exception: Exception? = null
|
||||||
) {
|
) {
|
||||||
val name = folder.name
|
val name = folder.name
|
||||||
|
|
||||||
val isError = nameError != null
|
val isTextFieldError = nameError != null
|
||||||
}
|
}
|
@ -17,13 +17,18 @@ import androidx.compose.material3.IconButton
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SmallFloatingActionButton
|
import androidx.compose.material3.SmallFloatingActionButton
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.painterResource
|
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.FeedModalBottomSheet
|
||||||
import com.readrops.app.compose.feeds.dialogs.FolderDialog
|
import com.readrops.app.compose.feeds.dialogs.FolderDialog
|
||||||
import com.readrops.app.compose.feeds.dialogs.UpdateFeedDialog
|
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.CenteredProgressIndicator
|
||||||
import com.readrops.app.compose.util.components.ErrorMessage
|
import com.readrops.app.compose.util.components.ErrorMessage
|
||||||
import com.readrops.app.compose.util.components.Placeholder
|
import com.readrops.app.compose.util.components.Placeholder
|
||||||
@ -59,11 +65,20 @@ object FeedTab : Tab {
|
|||||||
override fun Content() {
|
override fun Content() {
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
val viewModel = getScreenModel<FeedScreenModel>()
|
val viewModel = getScreenModel<FeedScreenModel>()
|
||||||
|
|
||||||
val state by viewModel.feedsState.collectAsStateWithLifecycle()
|
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) {
|
when (val dialog = state.dialog) {
|
||||||
is DialogState.AddFeed -> {
|
is DialogState.AddFeed -> {
|
||||||
AddFeedDialog(
|
AddFeedDialog(
|
||||||
@ -204,7 +219,8 @@ object FeedTab : Tab {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
snackbarHost = { SnackbarHost(snackbarHostState) }
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -4,16 +4,19 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Clear
|
import androidx.compose.material.icons.filled.Clear
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.readrops.app.compose.R
|
import com.readrops.app.compose.R
|
||||||
import com.readrops.app.compose.feeds.FeedScreenModel
|
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.components.BaseDialog
|
||||||
import com.readrops.app.compose.util.theme.LargeSpacer
|
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()) }
|
supportingText = { Text(text = state.nameError?.errorText().orEmpty()) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (state.exception != null) {
|
||||||
|
Text(
|
||||||
|
text = ErrorMessage.get(state.exception!!, LocalContext.current),
|
||||||
|
color = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
LargeSpacer()
|
LargeSpacer()
|
||||||
|
|
||||||
TextButton(
|
TextButton(
|
||||||
|
@ -85,8 +85,18 @@ class FreshRSSRepository(
|
|||||||
override suspend fun insertNewFeeds(
|
override suspend fun insertNewFeeds(
|
||||||
newFeeds: List<Feed>,
|
newFeeds: List<Feed>,
|
||||||
onUpdate: (Feed) -> Unit
|
onUpdate: (Feed) -> Unit
|
||||||
): ErrorResult {
|
): ErrorResult = TODO("Not yet implemented")
|
||||||
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>) {
|
private suspend fun insertFeeds(feeds: List<Feed>) {
|
||||||
|
@ -25,6 +25,7 @@ class GetFoldersWithFeeds(
|
|||||||
Folder(
|
Folder(
|
||||||
id = it.folderId!!,
|
id = it.folderId!!,
|
||||||
name = it.folderName,
|
name = it.folderName,
|
||||||
|
remoteId = it.folderRemoteId,
|
||||||
accountId = it.accountId
|
accountId = it.accountId
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,14 +13,14 @@ 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,
|
Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription, Folder.id As folderId,
|
||||||
Folder.id As folderId, Folder.name As folderName, Feed.account_id as accountId
|
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,
|
Feed.siteUrl As feedSiteUrl, Feed.description as feedDescription,Folder.id As folderId,
|
||||||
Folder.id As folderId, Folder.name As folderName, Folder.account_id as accountId
|
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
|
||||||
""")
|
""")
|
||||||
|
@ -15,6 +15,7 @@ data class FeedWithFolder(
|
|||||||
data class FolderWithFeed(
|
data class FolderWithFeed(
|
||||||
val folderId: Int?,
|
val folderId: Int?,
|
||||||
val folderName: String?,
|
val folderName: String?,
|
||||||
|
val folderRemoteId: String?,
|
||||||
val feedId: Int = 0,
|
val feedId: Int = 0,
|
||||||
val feedName: String? = null,
|
val feedName: String? = null,
|
||||||
val feedIcon: String? = null,
|
val feedIcon: String? = null,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user