Skip to content

Commit

Permalink
Fix notification index bug
Browse files Browse the repository at this point in the history
  • Loading branch information
jocmp committed Jan 30, 2025
1 parent 207735c commit c1a31e2
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,6 @@ class NotificationHelper(
const val FEED_ID_KEY = "feed_id"
private const val ARTICLE_REFRESH_GROUP = "article_refresh"

/**
* Clear notification via broadcast receiver
*/
fun clearNotificationAsync(articleID: String, context: Context) {
DeleteNotificationWorker.performAsync(articleID, context = context)
}

fun dismissNotificationIntent(articleID: String, context: Context): Intent {
return Intent(context, ArticleStatusBroadcastReceiver::class.java).apply {
action = ArticleStatusBroadcastReceiver.ACTION_DISMISS_NOTIFICATION
Expand All @@ -137,7 +130,7 @@ class NotificationHelper(
appPreferences.filter.set(
ArticleFilter.Feeds(
feedID,
feedStatus = ArticleStatus.UNREAD,
feedStatus = ArticleStatus.ALL,
folderTitle = null
)
)
Expand Down
56 changes: 20 additions & 36 deletions app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.capyreader.app.ui.articles

import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -58,8 +60,6 @@ import com.jocmp.capy.Folder
import com.jocmp.capy.MarkRead
import com.jocmp.capy.SavedSearch
import com.jocmp.capy.common.launchUI
import com.jocmp.capy.logging.CapyLog
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@OptIn(
Expand All @@ -79,6 +79,7 @@ fun ArticleLayout(
search: ArticleSearch,
statusCount: Long,
refreshInterval: RefreshInterval,
onInitialized: (completion: () -> Unit) -> Unit,
onFeedRefresh: (completion: () -> Unit) -> Unit,
onSelectFolder: (folderTitle: String) -> Unit,
onSelectSavedSearch: (savedSearchID: String) -> Unit,
Expand Down Expand Up @@ -122,7 +123,6 @@ fun ArticleLayout(
onUnauthorizedDismissRequest()
setUpdatePasswordDialogOpen(true)
}
var listVisible by remember { mutableStateOf(true) }

suspend fun navigateToDetail() {
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
Expand All @@ -141,24 +141,9 @@ fun ArticleLayout(
scrollBehavior = scrollBehavior
)

suspend fun resetListVisibility() {
listState.scrollToItem(0)
resetScrollBehaviorOffset()
listVisible = true
}

suspend fun openNextStatus(action: suspend () -> Unit) {
listVisible = false
delay(150)
action()
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.List)

coroutineScope.launch {
delay(300)
if (!listVisible) {
resetListVisibility()
}
}
}

fun requestNextFeed() {
Expand Down Expand Up @@ -198,21 +183,27 @@ fun ArticleLayout(
}
}

fun refreshFeeds() {
fun initialize() {
isRefreshing = true
onFeedRefresh {
onInitialized {
isRefreshing = false
refreshPagination()

if (!isInitialized) {
setInitialized(true)
}
}
}

fun refreshFeeds() {
isRefreshing = true
onFeedRefresh {
isRefreshing = false
refreshPagination()
}
}

fun openNextList(action: suspend () -> Unit) {
coroutineScope.launchUI {
listVisible = false
drawerState.close()
openNextStatus(action)
}
Expand Down Expand Up @@ -404,20 +395,20 @@ fun ArticleLayout(
requestNextFeed()
},
) {
AnimatedVisibility(
listVisible,
enter = fadeIn(),
exit = fadeOut(),
Crossfade(
articles,
animationSpec = tween(500),
modifier = Modifier.fillMaxSize(),
label = "",
) {
ArticleList(
articles = articles,
articles = it,
selectedArticleKey = article?.id,
listState = listState,
onMarkAllRead = { range ->
onMarkAllRead(range)
},
onSelect = { selectArticle(it) },
onSelect = ::selectArticle,
)
}
}
Expand Down Expand Up @@ -459,7 +450,6 @@ fun ArticleLayout(
)

LaunchedEffect(article.id, indexedArticles.index) {
CapyLog.info("callback", mapOf("index" to indexedArticles.index.toString()))
if (hasMultipleColumns) {
scrollToArticle(indexedArticles.index)
}
Expand Down Expand Up @@ -502,7 +492,7 @@ fun ArticleLayout(

LaunchedEffect(Unit) {
if (!isInitialized) {
refreshFeeds()
initialize()
}
}

Expand All @@ -525,12 +515,6 @@ fun ArticleLayout(
) {
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.List)
}

LaunchedEffect(articles.itemCount) {
if (!listVisible) {
resetListVisibility()
}
}
}

fun canOpenNextFeed(
Expand Down
14 changes: 10 additions & 4 deletions app/src/main/java/com/capyreader/app/ui/articles/ArticleScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ fun ArticleScreen(
val savedSearches by viewModel.savedSearches.collectAsStateWithLifecycle(initialValue = emptyList())
val statusCount by viewModel.statusCount.collectAsStateWithLifecycle(initialValue = 0)
val filter by viewModel.filter.collectAsStateWithLifecycle(appPreferences.filter.get())
val articlesSince by viewModel.articlesSince.collectAsStateWithLifecycle()
val unreadSort by viewModel.unreadSort.collectAsStateWithLifecycle()
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 afterReadAll by viewModel.afterReadAll.collectAsStateWithLifecycle()
Expand All @@ -44,6 +45,12 @@ fun ArticleScreen(
val connectivity = rememberLocalConnectivity()
val drawerState = rememberDrawerState(DrawerValue.Closed)

val pager = remember(filter, unreadSort, articlesSince) {
viewModel.pager(filter, unreadSort, articlesSince)
}

val articles = pager.flow.collectAsLazyPagingItems()

CompositionLocalProvider(
LocalFullContent provides fullContent,
LocalArticleActions provides articleActions,
Expand All @@ -60,9 +67,8 @@ fun ArticleScreen(
article = viewModel.article,
statusCount = statusCount,
refreshInterval = appPreferences.refreshInterval.get(),
onFeedRefresh = { completion ->
viewModel.refreshFeed(completion)
},
onInitialized = viewModel::initialize,
onFeedRefresh = viewModel::refreshFeed,
drawerState = drawerState,
onSelectFolder = viewModel::selectFolder,
onSelectFeed = viewModel::selectFeed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.capyreader.app.R
import com.capyreader.app.common.AfterReadAllBehavior
import com.capyreader.app.common.AppPreferences
Expand All @@ -24,6 +23,7 @@ import com.jocmp.capy.MarkRead
import com.jocmp.capy.SavedSearch
import com.jocmp.capy.articles.ArticleContent
import com.jocmp.capy.articles.NextFilter
import com.jocmp.capy.articles.UnreadSortOrder
import com.jocmp.capy.buildArticlePager
import com.jocmp.capy.common.UnauthorizedError
import com.jocmp.capy.common.launchIO
Expand Down Expand Up @@ -56,11 +56,11 @@ class ArticleScreenViewModel(

private var _article by mutableStateOf<Article?>(null)

private val articlesSince = MutableStateFlow<OffsetDateTime>(OffsetDateTime.now())
val articlesSince = MutableStateFlow<OffsetDateTime>(OffsetDateTime.now())

private var _showUnauthorizedMessage by mutableStateOf(UnauthorizedMessageState.HIDE)

private val unreadSort = appPreferences.articleListOptions.unreadSort.stateIn(viewModelScope)
val unreadSort = appPreferences.articleListOptions.unreadSort.stateIn(viewModelScope)

val afterReadAll =
appPreferences.articleListOptions.afterReadAllBehavior.stateIn(viewModelScope)
Expand All @@ -69,20 +69,17 @@ class ArticleScreenViewModel(
account.countAll(latestFilter.status)
}

val articles: Flow<PagingData<Article>> =
combine(
filter,
_searchQuery,
articlesSince,
unreadSort
) { filter, query, since, sort ->
account.buildArticlePager(
filter = filter,
query = query,
unreadSort = sort,
since = since
).flow
}.flatMapLatest { it }
fun pager(
filter: ArticleFilter,
sort: UnreadSortOrder,
since: OffsetDateTime,
) =
account.buildArticlePager(
filter = filter,
query = "",
unreadSort = sort,
since = since
)

val folders: Flow<List<Folder>> = combine(
account.folders,
Expand Down Expand Up @@ -246,7 +243,7 @@ class ArticleScreenViewModel(
}
}

fun refreshFeed(onComplete: () -> Unit) {
fun initialize(onComplete: () -> Unit) {
refreshJob?.cancel()

refreshJob = viewModelScope.launch(Dispatchers.IO) {
Expand All @@ -256,8 +253,13 @@ class ArticleScreenViewModel(
}
}

updateArticlesSince()
onComplete()
}
}

fun refreshFeed(onComplete: () -> Unit) {
initialize {
updateArticlesSince()
onComplete()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.paging.compose.LazyPagingItems
import com.jocmp.capy.Article
import com.jocmp.capy.logging.CapyLog

data class IndexedArticles(
val index: Int,
Expand Down Expand Up @@ -39,10 +38,9 @@ fun rememberIndexedArticles(
return remember(article, snapshot.size) {
val index = snapshot.indexOfFirst { it?.id == article.id }

// trigger reload of snapshot list
if (index > -1) {
CapyLog.info("index", mapOf("index" to index.toString()))
articles.get(index)
// Trigger reload of snapshot list
if (index > -1 && articles.peek(index) == null) {
articles[index]
}

IndexedArticles(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ fun ArticleReader(
Spacer(modifier = Modifier.height(120.dp))
}
}

}

LaunchedEffect(article.id, article.content) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import com.capyreader.app.ui.components.pullrefresh.SwipeRefresh
import com.capyreader.app.ui.settings.panels.ArticleVerticalSwipe
import com.capyreader.app.ui.settings.panels.ArticleVerticalSwipe.LOAD_FULL_CONTENT
import com.jocmp.capy.Article
import com.jocmp.capy.logging.CapyLog
import org.koin.compose.koinInject

@OptIn(ExperimentalMaterial3Api::class)
Expand Down Expand Up @@ -103,15 +102,17 @@ fun ArticleView(
)
},
reader = {
HorizontalPager(state = pagerState) { page ->
HorizontalPager(
state = pagerState,
beyondViewportPageCount = 1,
) { page ->
ArticlePullRefresh(
toolbars.show && !toolbars.pinned,
onToggleFullContent = onToggleFullContent,
onRequestNext = onRequestNext,
onRequestPrevious = onRequestPrevious,
articles = articles,
) {
CapyLog.info("reader", mapOf("page" to page.toString()))
articles.find(page)?.let { pagedArticle ->
ArticleReader(
article = currentArticle(article, pagedArticle),
Expand Down Expand Up @@ -180,15 +181,6 @@ private fun ArticleViewScaffold(
bottomBar()
}
}

if (!toolbarPreferences.pinned) {
BarVisibility(
modifier = Modifier.align(Alignment.BottomCenter),
visible = toolbarPreferences.show,
) {
bottomBar()
}
}
}

if (!toolbarPreferences.pinned) {
Expand Down Expand Up @@ -336,6 +328,14 @@ fun currentArticle(article: Article, pagedArticle: Article): Article {
return if (article.id == pagedArticle.id) {
article
} else {
pagedArticle
pagedArticle.withPlaceholderContent()
}
}

private fun Article.withPlaceholderContent(): Article {
return if (enableStickyFullContent) {
copy(summary = "", content = "")
} else {
this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ internal fun listMapper(
publishedAt: Long?,
feedTitle: String?,
faviconURL: String?,
enableStickyContent: Boolean,
updatedAt: Long?,
starred: Boolean?,
read: Boolean?,
Expand All @@ -71,6 +72,7 @@ internal fun listMapper(
author = author,
contentHtml = contentHtml,
extractedContentURL = extractedContentURL,
enableStickyContent = enableStickyContent,
feedURL = null,
siteURL = null,
url = url,
Expand Down
Loading

0 comments on commit c1a31e2

Please sign in to comment.