Skip to content

Commit

Permalink
Extract NextFilter module
Browse files Browse the repository at this point in the history
  • Loading branch information
jocmp committed Dec 9, 2024
1 parent beba906 commit c99a22c
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -342,6 +343,7 @@ fun ArticleLayout(
}
} else {
PullToNextFeedBox(
enabled = canSwipeToNextFeed,
onRequestNext = {
coroutineScope.launchUI {
openNextStatus {
Expand Down Expand Up @@ -463,7 +465,7 @@ fun ArticleLayout(
toggleDrawer()
}

LaunchedEffect(pagingArticles.itemCount) {
LaunchedEffect(pagingArticles.itemCount, filter) {
if (!listVisible) {
listState.scrollToItem(0)
listVisible = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -93,6 +94,13 @@ class ArticleScreenViewModel(
.withPositiveCount(filter.status)
}

private val nextFilterListener: Flow<NextFilter?> =
combine(feeds, folders, filter) { feeds, folders, filter ->
NextFilter.find(filter, feeds, folders)
}

private val _nextFilter = MutableStateFlow<NextFilter?>(null)

val statusCount: Flow<Long> = _counts.map {
it.values.sum()
}
Expand All @@ -106,16 +114,27 @@ class ArticleScreenViewModel(
val searchQuery: Flow<String?>
get() = _searchQuery

val nextFilter: Flow<NextFilter?>
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) {
Expand Down Expand Up @@ -276,54 +295,17 @@ class ArticleScreenViewModel(
markUnread(articleID)
}

fun onRequestNextFeed(feeds: List<Feed>, folders: List<Folder>) = 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) {
Expand Down Expand Up @@ -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()

Expand Down
73 changes: 73 additions & 0 deletions capy/src/main/java/com/jocmp/capy/articles/NextFilter.kt
Original file line number Diff line number Diff line change
@@ -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<Feed>,
folders: List<Folder>,
): 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
}
}
}
}
}
}
}

0 comments on commit c99a22c

Please sign in to comment.