diff --git a/appcompose/src/main/java/com/readrops/app/compose/timelime/FilterBottomSheet.kt b/appcompose/src/main/java/com/readrops/app/compose/timelime/FilterBottomSheet.kt new file mode 100644 index 00000000..357bdcf9 --- /dev/null +++ b/appcompose/src/main/java/com/readrops/app/compose/timelime/FilterBottomSheet.kt @@ -0,0 +1,93 @@ +package com.readrops.app.compose.timelime + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.readrops.app.compose.R +import com.readrops.app.compose.util.theme.LargeSpacer +import com.readrops.app.compose.util.theme.ShortSpacer +import com.readrops.app.compose.util.theme.spacing +import com.readrops.db.filters.ListSortType +import com.readrops.db.queries.QueryFilters + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FilterBottomSheet( + viewModel: TimelineViewModel, + filters: QueryFilters, + onDismiss: () -> Unit, +) { + ModalBottomSheet( + onDismissRequest = onDismiss + ) { + Column( + modifier = Modifier.padding(MaterialTheme.spacing.mediumSpacing) + ) { + Text( + text = stringResource(R.string.filters) + ) + + ShortSpacer() + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .clickable { viewModel.setShowReadItemsState(!filters.showReadItems) } + ) { + Checkbox( + checked = filters.showReadItems, + onCheckedChange = { viewModel.setShowReadItemsState(!filters.showReadItems) } + ) + + ShortSpacer() + + Text( + text = stringResource(R.string.show_read_articles) + ) + } + + ShortSpacer() + + fun setSortTypeState() { + viewModel.setSortTypeState( + if (filters.sortType == ListSortType.NEWEST_TO_OLDEST) + ListSortType.OLDEST_TO_NEWEST + else + ListSortType.NEWEST_TO_OLDEST + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .clickable { setSortTypeState() } + ) { + Checkbox( + checked = filters.sortType == ListSortType.OLDEST_TO_NEWEST, + onCheckedChange = { setSortTypeState() } + ) + + ShortSpacer() + + Text( + text = "Show oldest items first" + ) + } + + LargeSpacer() + } + } +} \ No newline at end of file diff --git a/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineTab.kt b/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineTab.kt index ea421bf0..faf7febf 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineTab.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineTab.kt @@ -97,19 +97,33 @@ object TimelineTab : Tab { } } - if (state.confirmDialog) { - TwoChoicesDialog( - title = "Mark all items as read", - text = "Do you really want to mark all items as read?", - icon = painterResource(id = R.drawable.ic_rss_feed_grey), - confirmText = "Validate", - dismissText = "Cancel", - onDismiss = { viewModel.closeConfirmDialog() }, - onConfirm = { - viewModel.closeConfirmDialog() - viewModel.setAllItemsRead() - } - ) + when (state.dialog) { + DialogState.ConfirmDialog -> { + TwoChoicesDialog( + title = "Mark all items as read", + text = "Do you really want to mark all items as read?", + icon = painterResource(id = R.drawable.ic_rss_feed_grey), + confirmText = "Validate", + dismissText = "Cancel", + onDismiss = { viewModel.closeDialog() }, + onConfirm = { + viewModel.closeDialog() + viewModel.setAllItemsRead() + } + ) + } + + DialogState.FilterSheet -> { + FilterBottomSheet( + viewModel = viewModel, + filters = state.filters, + onDismiss = { + viewModel.closeDialog() + } + ) + } + + null -> {} } ModalNavigationDrawer( @@ -155,7 +169,9 @@ object TimelineTab : Tab { } }, actions = { - IconButton(onClick = { }) { + IconButton( + onClick = { viewModel.openDialog(DialogState.FilterSheet) } + ) { Icon( painter = painterResource(id = R.drawable.ic_filter_list), contentDescription = null @@ -177,7 +193,7 @@ object TimelineTab : Tab { FloatingActionButton( onClick = { if (state.filters.filterType == FilterType.NO_FILTER) { - viewModel.openConfirmDialog() + viewModel.openDialog(DialogState.ConfirmDialog) } else { viewModel.setAllItemsRead() } diff --git a/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineViewModel.kt b/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineViewModel.kt index e0433b6a..b9945429 100644 --- a/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineViewModel.kt +++ b/appcompose/src/main/java/com/readrops/app/compose/timelime/TimelineViewModel.kt @@ -15,6 +15,7 @@ import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder import com.readrops.db.entities.Item import com.readrops.db.filters.FilterType +import com.readrops.db.filters.ListSortType import com.readrops.db.pojo.ItemWithFeed import com.readrops.db.queries.ItemsQueryBuilder import com.readrops.db.queries.QueryFilters @@ -197,6 +198,7 @@ class TimelineViewModel( _timelineState.value.filters.filterFolderId, currentAccount!!.id ) + FilterType.READ_IT_LATER_FILTER -> TODO() FilterType.STARS_FILTER -> repository?.setAllStarredItemsRead(currentAccount!!.id) FilterType.NO_FILTER -> repository?.setAllItemsRead(currentAccount!!.id) @@ -205,16 +207,32 @@ class TimelineViewModel( } } - fun openConfirmDialog() { - _timelineState.value = _timelineState.value.copy( - confirmDialog = true - ) + fun openDialog(dialog: DialogState) = _timelineState.update { it.copy(dialog = dialog) } + + fun closeDialog() = _timelineState.update { it.copy(dialog = null) } + + fun setShowReadItemsState(showReadItems: Boolean) { + _timelineState.update { + it.copy( + filters = updateFilters { + it.filters.copy( + showReadItems = showReadItems + ) + } + ) + } } - fun closeConfirmDialog() { - _timelineState.value = _timelineState.value.copy( - confirmDialog = false - ) + fun setSortTypeState(sortType: ListSortType) { + _timelineState.update { + it.copy( + filters = updateFilters { + it.filters.copy( + sortType = sortType + ) + } + ) + } } } @@ -228,5 +246,10 @@ data class TimelineState( val filterFolderName: String = "", val foldersAndFeeds: Map> = emptyMap(), val itemState: Flow> = emptyFlow(), - val confirmDialog: Boolean = false + val dialog: DialogState? = null ) + +sealed interface DialogState { + object ConfirmDialog : DialogState + object FilterSheet : DialogState +} diff --git a/appcompose/src/main/res/values-fr/strings.xml b/appcompose/src/main/res/values-fr/strings.xml index 3384ba26..e0d77928 100644 --- a/appcompose/src/main/res/values-fr/strings.xml +++ b/appcompose/src/main/res/values-fr/strings.xml @@ -73,6 +73,7 @@ Du plus ancien au plus récent La connexion a échoué. Veuillez vérifier vos identifiants Nouveau compte + Nouveaux articles Appli distribuée sous la licence GPLv3 Nombre maximum d\'articles par flux Illimité @@ -140,5 +141,6 @@ Thème du système Cacher les flux sans nouveaux items Marquer les items comme lus pendant le défilement + Filtres \ No newline at end of file diff --git a/appcompose/src/main/res/values/strings.xml b/appcompose/src/main/res/values/strings.xml index 272ac80c..1f651913 100644 --- a/appcompose/src/main/res/values/strings.xml +++ b/appcompose/src/main/res/values/strings.xml @@ -147,4 +147,5 @@ Hide feeds without new items Mark items read on scroll New articles + Filters \ No newline at end of file