Skip to content

Commit bd318bb

Browse files
committed
Use pointers instead of recalc'ing next filter
1 parent 71376e8 commit bd318bb

14 files changed

Lines changed: 669 additions & 837 deletions

File tree

app/src/main/java/com/capyreader/app/preferences/ArticleListVerticalSwipe.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import com.capyreader.app.R
44

55
enum class ArticleListVerticalSwipe {
66
DISABLED,
7-
NEXT_FEED;
7+
NEXT_FEED,
8+
MARK_ALL_READ;
89

910
val translationKey: Int
1011
get() = when (this) {
1112
DISABLED -> R.string.article_list_swipe_disabled
1213
NEXT_FEED -> R.string.article_list_swipe_next_feed
14+
MARK_ALL_READ -> R.string.article_list_swipe_mark_all_read
1315
}
1416

1517
companion object {

app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt

Lines changed: 141 additions & 105 deletions
Large diffs are not rendered by default.

app/src/main/java/com/capyreader/app/ui/articles/ArticleScreenViewModel.kt

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.jocmp.capy.Folder
2727
import com.jocmp.capy.MarkRead
2828
import com.jocmp.capy.SavedSearch
2929
import com.jocmp.capy.articles.ArticleContent
30-
import com.jocmp.capy.articles.NextFilter
30+
import com.jocmp.capy.articles.SidebarItem
3131
import com.jocmp.capy.common.UnauthorizedError
3232
import com.jocmp.capy.common.launchIO
3333
import com.jocmp.capy.common.launchUI
@@ -61,7 +61,7 @@ class ArticleScreenViewModel(
6161
val hideReadArticles =
6262
appPreferences.articleListOptions.hideReadArticles.stateIn(viewModelScope)
6363

64-
private val listSwipeBottom =
64+
val listSwipeBottom =
6565
appPreferences.articleListOptions.swipeBottom.stateIn(viewModelScope)
6666

6767
private val _searchQuery = MutableStateFlow("")
@@ -148,28 +148,35 @@ class ArticleScreenViewModel(
148148
?.takeIf { it.count > 0 || filter.status != ArticleStatus.UNREAD }
149149
}
150150

151-
private val nextFilterListener: Flow<NextFilter?> =
151+
private val sidebar: Flow<List<SidebarItem>> = combine(
152+
readLaterFeed,
153+
savedSearches,
154+
folders,
155+
topLevelFeeds,
156+
) { readLater, searches, fldrs, fds ->
157+
SidebarItem.buildList(
158+
readLaterFeed = readLater,
159+
savedSearches = searches,
160+
folders = fldrs,
161+
feeds = fds,
162+
)
163+
}
164+
165+
private val _nextItem = MutableStateFlow<SidebarItem?>(null)
166+
167+
private val nextItemListener: Flow<SidebarItem?> =
152168
combine(
153169
listSwipeBottom,
154-
savedSearches,
155-
topLevelFeeds,
156-
folders,
157-
filter
158-
) { swipeBottom, savedSearches, feeds, folders, filter ->
170+
sidebar,
171+
filter,
172+
) { swipeBottom, sidebar, filter ->
159173
if (swipeBottom == ArticleListVerticalSwipe.DISABLED) {
160174
return@combine null
161175
}
162176

163-
NextFilter.findSwipeDestination(
164-
filter,
165-
searches = savedSearches,
166-
folders = folders,
167-
feeds = feeds,
168-
)
177+
sidebar.find { it.isSelected(filter) }?.next
169178
}
170179

171-
private val _nextFilter = MutableStateFlow<NextFilter?>(null)
172-
173180
val statusCount: Flow<Long> = filter.flatMapLatest { latestFilter ->
174181
account.countAllByStatus(countableStatus(latestFilter))
175182
}
@@ -202,13 +209,13 @@ class ArticleScreenViewModel(
202209
val searchState: Flow<SearchState>
203210
get() = _searchState
204211

205-
val nextFilter: Flow<NextFilter?>
206-
get() = _nextFilter
212+
val nextFilter: Flow<SidebarItem?>
213+
get() = _nextItem
207214

208215
init {
209216
viewModelScope.launch {
210-
nextFilterListener.collect {
211-
_nextFilter.value = it
217+
nextItemListener.collect {
218+
_nextItem.value = it
212219
}
213220
}
214221
}
@@ -268,9 +275,6 @@ class ArticleScreenViewModel(
268275
fun markAllRead(
269276
onArticlesCleared: () -> Unit,
270277
range: MarkRead,
271-
searches: List<SavedSearch>,
272-
folders: List<Folder>,
273-
feeds: List<Feed>,
274278
) {
275279
viewModelScope.launchIO {
276280
val articleIDs = account.unreadArticleIDs(
@@ -295,7 +299,7 @@ class ArticleScreenViewModel(
295299
if (afterReadAll.value == AfterReadAllBehavior.OPEN_DRAWER) {
296300
onArticlesCleared()
297301
} else if (afterReadAll.value == AfterReadAllBehavior.OPEN_NEXT_FEED) {
298-
openNextFeedOnAllRead(onArticlesCleared, searches, folders, feeds)
302+
openNextFeedOnAllRead(onArticlesCleared)
299303
}
300304
}
301305
}
@@ -491,19 +495,12 @@ class ArticleScreenViewModel(
491495
}
492496

493497
fun requestNextFeed() {
494-
_nextFilter.value?.let(::selectNextFilter)
498+
_nextItem.value?.let(::selectSidebarItem)
495499
}
496500

497-
private fun selectNextFilter(filter: NextFilter) {
498-
when (filter) {
499-
is NextFilter.FeedFilter -> selectFeed(
500-
feedID = filter.feedID,
501-
folderTitle = filter.folderTitle
502-
)
503-
504-
is NextFilter.FolderFilter -> selectFolder(title = filter.folderTitle)
505-
is NextFilter.SearchFilter -> selectSavedSearch(filter.savedSearchID)
506-
}
501+
private fun selectSidebarItem(item: SidebarItem) {
502+
val filter = item.toFilter(currentStatus)
503+
updateFilter(filter)
507504
}
508505

509506
private fun addStar(articleID: String) {
@@ -681,19 +678,11 @@ class ArticleScreenViewModel(
681678

682679
private fun openNextFeedOnAllRead(
683680
onArticlesCleared: () -> Unit,
684-
searches: List<SavedSearch>,
685-
folders: List<Folder>,
686-
feeds: List<Feed>,
687681
) {
688-
val nextFilter = NextFilter.findMarkReadDestination(
689-
latestFilter,
690-
searches,
691-
folders,
692-
feeds,
693-
)
682+
val nextItem = _nextItem.value
694683

695-
if (nextFilter != null) {
696-
selectNextFilter(nextFilter)
684+
if (nextItem != null) {
685+
selectSidebarItem(nextItem)
697686
} else {
698687
if (latestFilter.status == UNREAD) {
699688
selectArticleFilter()

app/src/main/java/com/capyreader/app/ui/articles/FilterActionMenu.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import com.jocmp.capy.Feed
2424
@Composable
2525
fun FilterActionMenu(
2626
filter: ArticleFilter,
27-
onMarkAllRead: () -> Unit,
2827
onRequestSearch: () -> Unit,
2928
hideSearchIcon: Boolean,
3029
hideReadArticles: Boolean = false,
@@ -64,11 +63,7 @@ fun FilterActionMenu(
6463
}
6564

6665
if (markReadPosition == MarkReadPosition.TOOLBAR) {
67-
MarkAllReadButton(
68-
onMarkAllRead = {
69-
onMarkAllRead()
70-
},
71-
)
66+
MarkAllReadButton()
7267
}
7368
}
7469
}
@@ -78,7 +73,6 @@ fun FilterActionMenu(
7873
fun FeedActionsPreview(@PreviewParameter(FeedSample::class) feed: Feed) {
7974
PreviewKoinApplication {
8075
FilterActionMenu(
81-
onMarkAllRead = {},
8276
onRequestSearch = {},
8377
filter = ArticleFilter.Feeds(
8478
feedID = feed.id,
@@ -96,7 +90,6 @@ fun FeedActionsPreview(@PreviewParameter(FeedSample::class) feed: Feed) {
9690
fun FeedActionsPreviewFilterOff(@PreviewParameter(FeedSample::class) feed: Feed) {
9791
PreviewKoinApplication {
9892
FilterActionMenu(
99-
onMarkAllRead = {},
10093
onRequestSearch = {},
10194
filter = ArticleFilter.Feeds(
10295
feedID = feed.id,

app/src/main/java/com/capyreader/app/ui/articles/list/ArticleListTopBar.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ fun ArticleListTopBar(
4343
onRequestJumpToTop: () -> Unit,
4444
onNavigateToDrawer: () -> Unit,
4545
scrollBehavior: TopAppBarScrollBehavior,
46-
onMarkAllRead: () -> Unit,
4746
search: ArticleSearch,
4847
filter: ArticleFilter,
4948
feeds: List<Feed>,
@@ -139,7 +138,6 @@ fun ArticleListTopBar(
139138
FilterActionMenu(
140139
filter = filter,
141140
onRequestSearch = { search.start() },
142-
onMarkAllRead = { onMarkAllRead() },
143141
hideSearchIcon = enableSearch,
144142
hideReadArticles = hideReadArticles,
145143
onToggleHideReadArticles = onToggleHideReadArticles,
@@ -157,7 +155,6 @@ private fun FeedListTopBarPreview() {
157155
onRequestJumpToTop = { },
158156
onNavigateToDrawer = { },
159157
scrollBehavior = scrollBehavior,
160-
onMarkAllRead = {},
161158
search = ArticleSearch(),
162159
filter = ArticleFilter.default(),
163160
feeds = listOf(),
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.capyreader.app.ui.articles.list
2+
3+
import androidx.compose.runtime.compositionLocalOf
4+
5+
val LocalMarkAllRead = compositionLocalOf<() -> Unit> { {} }

app/src/main/java/com/capyreader/app/ui/articles/list/MarkAllReadButton.kt

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,17 @@ import androidx.compose.material3.Icon
1111
import androidx.compose.material3.IconButton
1212
import androidx.compose.material3.MaterialTheme
1313
import androidx.compose.runtime.Composable
14-
import androidx.compose.runtime.getValue
15-
import androidx.compose.runtime.mutableStateOf
16-
import androidx.compose.runtime.remember
1714
import androidx.compose.ui.res.stringResource
1815
import com.capyreader.app.R
1916
import com.capyreader.app.ui.LocalUnreadCount
2017
import com.capyreader.app.ui.articles.MarkReadPosition
2118

2219
@Composable
2320
fun MarkAllReadButton(
24-
onMarkAllRead: () -> Unit,
2521
position: MarkReadPosition = MarkReadPosition.TOOLBAR,
2622
) {
2723
val unreadCount = LocalUnreadCount.current
28-
val confirmationEnabled by rememberMarkAllReadState()
29-
30-
val (isDialogOpen, setDialogOpen) = remember {
31-
mutableStateOf(false)
32-
}
33-
34-
val closeDialog = {
35-
setDialogOpen(false)
36-
}
37-
38-
val onClick = {
39-
if (confirmationEnabled) {
40-
setDialogOpen(true)
41-
} else {
42-
onMarkAllRead()
43-
}
44-
}
24+
val requestMarkAllRead = LocalMarkAllRead.current
4525

4626
if (position == MarkReadPosition.FLOATING_ACTION_BUTTON) {
4727
AnimatedVisibility(
@@ -52,9 +32,7 @@ fun MarkAllReadButton(
5232
FloatingActionButton(
5333
containerColor = MaterialTheme.colorScheme.primary,
5434
shape = CircleShape,
55-
onClick = {
56-
onClick()
57-
}
35+
onClick = { requestMarkAllRead() }
5836
) {
5937
Icon(
6038
imageVector = Icons.Filled.CheckCircle,
@@ -65,24 +43,12 @@ fun MarkAllReadButton(
6543
} else {
6644
IconButton(
6745
enabled = unreadCount > 0,
68-
onClick = {
69-
onClick()
70-
}
46+
onClick = { requestMarkAllRead() }
7147
) {
7248
Icon(
7349
imageVector = Icons.Filled.CheckCircle,
7450
contentDescription = stringResource(R.string.action_mark_all_read)
7551
)
7652
}
7753
}
78-
79-
if (isDialogOpen) {
80-
MarkAllReadDialog(
81-
onConfirm = {
82-
closeDialog()
83-
onMarkAllRead()
84-
},
85-
onDismissRequest = { closeDialog() }
86-
)
87-
}
8854
}

app/src/main/java/com/capyreader/app/ui/articles/list/MarkAllReadState.kt

Lines changed: 0 additions & 14 deletions
This file was deleted.

app/src/main/java/com/capyreader/app/ui/articles/list/PullToNextFeedBox.kt renamed to app/src/main/java/com/capyreader/app/ui/articles/list/SwipeUpActionBox.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback
1010
import com.capyreader.app.ui.components.pullrefresh.SwipeRefresh
1111

1212
@Composable
13-
fun PullToNextFeedBox(
13+
fun SwipeUpActionBox(
1414
modifier: Modifier = Modifier,
1515
enabled: Boolean = true,
1616
onRequestNext: () -> Unit,

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
<string name="article_list_row_swipe_toggle_read">Toggle Read</string>
257257
<string name="article_list_row_swipe_toggle_starred">Toggle Starred</string>
258258
<string name="article_list_swipe_next_feed">Go to next feed</string>
259+
<string name="article_list_swipe_mark_all_read">Mark all as read</string>
259260
<string name="article_list_swipe_disabled">Disabled</string>
260261
<string name="article_list_sort_title">Article Sort</string>
261262
<string name="article_list_sort_newest_first">Newest First</string>

0 commit comments

Comments
 (0)