diff --git a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt index 59cc627e..96961146 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt @@ -93,7 +93,8 @@ fun ArticleLayout( onRemoveFeed: (feedID: String, onSuccess: () -> Unit, onFailure: () -> Unit) -> Unit, drawerValue: DrawerValue = DrawerValue.Closed, showUnauthorizedMessage: Boolean, - onUnauthorizedDismissRequest: () -> Unit + onUnauthorizedDismissRequest: () -> Unit, + canSwipeToNextFeed: Boolean, ) { val skipInitialRefresh = refreshInterval == RefreshInterval.MANUALLY_ONLY @@ -342,6 +343,7 @@ fun ArticleLayout( } } else { PullToNextFeedBox( + enabled = canSwipeToNextFeed, onRequestNext = { coroutineScope.launchUI { openNextStatus { @@ -463,7 +465,7 @@ fun ArticleLayout( toggleDrawer() } - LaunchedEffect(pagingArticles.itemCount) { + LaunchedEffect(pagingArticles.itemCount, filter) { if (!listVisible) { listState.scrollToItem(0) listVisible = true diff --git a/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt b/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt index 3f1a3932..d9e6bc6b 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt @@ -28,6 +28,8 @@ fun ArticleScreen( val filter by viewModel.filter.collectAsStateWithLifecycle(appPreferences.filter.get()) val searchQuery by viewModel.searchQuery.collectAsState(initial = null) val articles = viewModel.articles.collectAsLazyPagingItems() + val nextFilter by viewModel.nextFilter.collectAsStateWithLifecycle(initialValue = null) + val canSwipeToNextFeed = nextFilter != null val fullContent = rememberFullContent(viewModel) val articleActions = rememberArticleActions(viewModel) @@ -64,9 +66,8 @@ fun ArticleScreen( onRemoveFeed = viewModel::removeFeed, showUnauthorizedMessage = viewModel.showUnauthorizedMessage, onUnauthorizedDismissRequest = viewModel::dismissUnauthorizedMessage, - onRequestNextFeed = { - viewModel.onRequestNextFeed(feeds, folders) - }, + onRequestNextFeed = viewModel::requestNextFeed, + canSwipeToNextFeed = canSwipeToNextFeed, search = ArticleSearch( query = searchQuery, clear = { viewModel.clearSearch() }, diff --git a/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreenViewModel.kt b/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreenViewModel.kt index 6153c53c..c141e1a5 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreenViewModel.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/ArticleScreenViewModel.kt @@ -17,6 +17,7 @@ import com.jocmp.capy.ArticleStatus import com.jocmp.capy.Feed import com.jocmp.capy.Folder import com.jocmp.capy.MarkRead +import com.jocmp.capy.articles.NextFilter import com.jocmp.capy.buildArticlePager import com.jocmp.capy.common.UnauthorizedError import com.jocmp.capy.common.launchIO @@ -93,6 +94,13 @@ class ArticleScreenViewModel( .withPositiveCount(filter.status) } + private val nextFilterListener: Flow = + combine(feeds, folders, filter) { feeds, folders, filter -> + NextFilter.find(filter, feeds, folders) + } + + private val _nextFilter = MutableStateFlow(null) + val statusCount: Flow = _counts.map { it.values.sum() } @@ -106,16 +114,27 @@ class ArticleScreenViewModel( val searchQuery: Flow get() = _searchQuery + val nextFilter: Flow + get() = _nextFilter + + init { + viewModelScope.launch { + nextFilterListener.collect { + _nextFilter.value = it + } + } + } + fun selectArticleFilter() { - val nextFilter = ArticleFilter.default().withStatus(status = latestFilter.status) + val filter = ArticleFilter.default().withStatus(status = latestFilter.status) - updateFilter(nextFilter) + updateFilter(filter) } fun selectStatus(status: ArticleStatus) { - val nextFilter = latestFilter.withStatus(status = status) + val filter = latestFilter.withStatus(status = status) - updateFilter(nextFilter) + updateFilter(filter) } fun selectFeed(feedID: String, folderTitle: String? = null) { @@ -276,54 +295,17 @@ class ArticleScreenViewModel( markUnread(articleID) } - fun onRequestNextFeed(feeds: List, folders: List) = viewModelScope.launchIO { - when (val currentFilter = filter.value) { - is ArticleFilter.Articles -> { - val firstFeed = feeds.firstOrNull() - val firstFolder = folders.firstOrNull() - - if (firstFolder != null) { - selectFolder(firstFolder.title) - } else if (firstFeed != null) { - selectFeed(feedID = firstFeed.id, folderTitle = null) - } - } - - is ArticleFilter.Folders -> { - val firstFeed = folders - .find { it.title == currentFilter.folderTitle } - ?.feeds - ?.firstOrNull() ?: return@launchIO - - selectFeed(feedID = firstFeed.id, folderTitle = currentFilter.folderTitle) - } - - is ArticleFilter.Feeds -> { - if (currentFilter.folderTitle == null) { - val index = feeds.indexOfFirst { it.id == currentFilter.feedID } - - val nextFeed = feeds.getOrNull(index + 1) ?: return@launchIO - - selectFeed(feedID = nextFeed.id, folderTitle = null) - } else { - val folderIndex = folders - .indexOfFirst { it.title == currentFilter.folderTitle } - - val folderFeeds = folders.getOrNull(folderIndex)?.feeds.orEmpty() - - val index = folderFeeds.indexOfFirst { it.id == currentFilter.feedID } - val nextFeed = folderFeeds.getOrNull(index + 1) - val nextFolder = folders.getOrNull(folderIndex + 1) + fun requestNextFeed() { + _nextFilter.value?.let { + when (it) { + is NextFilter.FeedFilter -> selectFeed( + feedID = it.feedID, + folderTitle = it.folderTitle + ) - if (nextFeed != null) { - selectFeed(feedID = nextFeed.id, folderTitle = currentFilter.folderTitle) - } else if (nextFolder != null) { - selectFolder(nextFolder.title) - } - } + is NextFilter.FolderFilter -> selectFolder(title = it.folderTitle) } } - // if filter is feed, select next feed } private fun addStar(articleID: String) { @@ -376,8 +358,8 @@ class ArticleScreenViewModel( } } - private fun updateFilter(nextFilter: ArticleFilter) { - appPreferences.filter.set(nextFilter) + private fun updateFilter(filter: ArticleFilter) { + appPreferences.filter.set(filter) updateArticlesSince() diff --git a/capy/src/main/java/com/jocmp/capy/articles/NextFilter.kt b/capy/src/main/java/com/jocmp/capy/articles/NextFilter.kt new file mode 100644 index 00000000..650ca541 --- /dev/null +++ b/capy/src/main/java/com/jocmp/capy/articles/NextFilter.kt @@ -0,0 +1,73 @@ +package com.jocmp.capy.articles + +import com.jocmp.capy.ArticleFilter +import com.jocmp.capy.Feed +import com.jocmp.capy.Folder + +sealed class NextFilter { + data class FolderFilter(val folderTitle: String) : NextFilter() + + data class FeedFilter(val feedID: String, val folderTitle: String? = null) : NextFilter() + + companion object { + fun find( + filter: ArticleFilter, + feeds: List, + folders: List, + ): NextFilter? { + return when (filter) { + is ArticleFilter.Articles -> { + val firstFeed = feeds.firstOrNull() + val firstFolder = folders.firstOrNull() + + if (firstFolder != null) { + FolderFilter(firstFolder.title) + } else if (firstFeed != null) { + FeedFilter(feedID = firstFeed.id, folderTitle = null) + } else { + null + } + } + + is ArticleFilter.Folders -> { + val firstFeed = folders + .find { it.title == filter.folderTitle } + ?.feeds + ?.firstOrNull() ?: return null + + FeedFilter(feedID = firstFeed.id, folderTitle = filter.folderTitle) + } + + is ArticleFilter.Feeds -> { + return if (filter.folderTitle == null) { + val index = feeds.indexOfFirst { it.id == filter.feedID } + + val nextFeed = feeds.getOrNull(index + 1) ?: return null + + FeedFilter(feedID = nextFeed.id, folderTitle = null) + } else { + val folderIndex = folders + .indexOfFirst { it.title == filter.folderTitle } + + val folderFeeds = folders.getOrNull(folderIndex)?.feeds.orEmpty() + + val index = folderFeeds.indexOfFirst { it.id == filter.feedID } + val nextFolderFeed = folderFeeds.getOrNull(index + 1) + val nextFolder = folders.getOrNull(folderIndex + 1) + val nextFeed = feeds.firstOrNull() + + if (nextFolderFeed != null) { + FeedFilter(feedID = nextFolderFeed.id, folderTitle = filter.folderTitle) + } else if (nextFolder != null) { + FolderFilter(nextFolder.title) + } else if (nextFeed != null) { + FeedFilter(feedID = nextFeed.id, folderTitle = null) + } else { + null + } + } + } + } + } + } +}