Improve pull feeds

This commit is contained in:
Ash 2022-03-25 03:08:19 +08:00
parent eda76f4445
commit 518dd6b59c
9 changed files with 94 additions and 31 deletions

View File

@ -72,7 +72,7 @@ abstract class AbstractRssRepository constructor(
fun pullFeeds(): Flow<MutableList<GroupWithFeed>> { fun pullFeeds(): Flow<MutableList<GroupWithFeed>> {
return groupDao.queryAllGroupWithFeed( return groupDao.queryAllGroupWithFeed(
context.dataStore.get(DataStoreKeys.CurrentAccountId) ?: 0 context.dataStore.get(DataStoreKeys.CurrentAccountId) ?: 0
) )//.flowOn(Dispatchers.IO)
} }
fun pullArticles( fun pullArticles(
@ -81,6 +81,7 @@ abstract class AbstractRssRepository constructor(
isStarred: Boolean = false, isStarred: Boolean = false,
isUnread: Boolean = false, isUnread: Boolean = false,
): PagingSource<Int, ArticleWithFeed> { ): PagingSource<Int, ArticleWithFeed> {
Log.i("RLog", "thread:pullArticles ${Thread.currentThread().name}")
val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId) ?: 0 val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId) ?: 0
Log.i( Log.i(
"RLog", "RLog",
@ -116,6 +117,7 @@ abstract class AbstractRssRepository constructor(
isUnread: Boolean = false, isUnread: Boolean = false,
): Flow<List<ImportantCount>> { ): Flow<List<ImportantCount>> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
Log.i("RLog", "thread:pullImportant ${Thread.currentThread().name}")
val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId)!! val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId)!!
Log.i( Log.i(
"RLog", "RLog",
@ -128,7 +130,7 @@ abstract class AbstractRssRepository constructor(
.queryImportantCountWhenIsUnread(accountId, isUnread) .queryImportantCountWhenIsUnread(accountId, isUnread)
else -> articleDao.queryImportantCountWhenIsAll(accountId) else -> articleDao.queryImportantCountWhenIsAll(accountId)
} }
} }//.flowOn(Dispatchers.IO)
} }
suspend fun findArticleById(id: String): ArticleWithFeed? { suspend fun findArticleById(id: String): ArticleWithFeed? {
@ -176,7 +178,6 @@ class SyncWorker @AssistedInject constructor(
15, TimeUnit.MINUTES 15, TimeUnit.MINUTES
).setConstraints( ).setConstraints(
Constraints.Builder() Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build() .build()
).addTag(WORK_NAME).build() ).addTag(WORK_NAME).build()
} }

View File

@ -87,8 +87,8 @@ class LocalRssRepository @Inject constructor(
override suspend fun sync() { override suspend fun sync() {
mutex.withLock { mutex.withLock {
val preTime = System.currentTimeMillis()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val preTime = System.currentTimeMillis()
val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId) val accountId = context.dataStore.get(DataStoreKeys.CurrentAccountId)
?: return@withContext ?: return@withContext
val feeds = async { feedDao.queryAll(accountId) } val feeds = async { feedDao.queryAll(accountId) }
@ -98,6 +98,7 @@ class LocalRssRepository @Inject constructor(
feedCount = feed.size, feedCount = feed.size,
) )
} }
Log.i("RLog", "thread:sync ${Thread.currentThread().name}")
}.map { feed -> }.map { feed ->
async { async {
val articles = syncFeed(accountId, feed) val articles = syncFeed(accountId, feed)
@ -132,36 +133,37 @@ class LocalRssRepository @Inject constructor(
private suspend fun syncFeed( private suspend fun syncFeed(
accountId: Int, accountId: Int,
feed: Feed feed: Feed
): MutableList<Article> { ): List<Article> {
val articles = mutableListOf<Article>()
val latest = articleDao.queryLatestByFeedId(accountId, feed.id) val latest = articleDao.queryLatestByFeedId(accountId, feed.id)
articles.addAll( val articles = rssHelper.queryRssXml(
rssHelper.queryRssXml( rssNetworkDataSource,
rssNetworkDataSource, accountId,
accountId, feed,
feed, latest?.link,
latest?.title, ).also {
).also { if (feed.icon == null && it.isNotEmpty()) {
if (feed.icon == null && it.isNotEmpty()) { rssHelper.queryRssIcon(feedDao, feed, it.first().link)
rssHelper.queryRssIcon(feedDao, feed, it.first().link)
}
} }
) }
Log.i("RLog", "thread:syncFeed ${Thread.currentThread().name}")
updateSyncState { updateSyncState {
it.copy( it.copy(
syncedCount = it.syncedCount + 1, syncedCount = it.syncedCount + 1,
currentFeedName = feed.name currentFeedName = feed.name
) )
} }
articleDao.insertList(articles) if (articles.isNotEmpty()) {
if (feed.isNotification) { articleDao.insertList(articles)
notify(articles) if (feed.isNotification) {
notify(articles)
}
} }
return articles return articles
} }
private fun notify( private fun notify(
articles: MutableList<Article>, articles: List<Article>,
) { ) {
articles.forEach { article -> articles.forEach { article ->
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(

View File

@ -92,13 +92,13 @@ class RssHelper @Inject constructor(
rssNetworkDataSource: RssNetworkDataSource, rssNetworkDataSource: RssNetworkDataSource,
accountId: Int, accountId: Int,
feed: Feed, feed: Feed,
latestTitle: String? = null, latestLink: String? = null,
): List<Article> { ): List<Article> {
val a = mutableListOf<Article>() val a = mutableListOf<Article>()
try { try {
val parseRss = rssNetworkDataSource.parseRss(feed.url) val parseRss = rssNetworkDataSource.parseRss(feed.url)
parseRss.items.forEach { parseRss.items.forEach {
if (latestTitle != null && latestTitle == it.title) return a if (latestLink != null && latestLink == it.link) return a
Log.i("RLog", "request rss ${feed.name}: ${it.title}") Log.i("RLog", "request rss ${feed.name}: ${it.title}")
a.add( a.add(
Article( Article(

View File

@ -0,0 +1,50 @@
package me.ash.reader.ui.page.home
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.data.constant.Filter
import me.ash.reader.ui.extension.getName
@OptIn(ExperimentalPagerApi::class)
@Composable
fun FilterBar2(
modifier: Modifier = Modifier,
filter: Filter,
onSelected: (Filter) -> Unit = {},
) {
NavigationBar(
tonalElevation = 0.dp,
) {
Spacer(modifier = Modifier.width(60.dp))
listOf(
Filter.Starred,
Filter.Unread,
Filter.All,
).forEach { item ->
NavigationBarItem(
icon = {
Icon(
imageVector = if (filter == item) item.filledIcon else item.icon,
contentDescription = item.getName()
)
},
// label = { Text(text = item.getName()) },
selected = filter == item,
onClick = { onSelected(item) },
colors = NavigationBarItemDefaults.colors(
selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer,
unselectedIconColor = MaterialTheme.colorScheme.outline,
selectedTextColor = MaterialTheme.colorScheme.onSurface,
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
indicatorColor = MaterialTheme.colorScheme.secondaryContainer,
)
)
}
Spacer(modifier = Modifier.width(60.dp))
}
}

View File

@ -113,7 +113,12 @@ fun HomeBottomNavBar(
.alpha(1 - readerBarAlpha), .alpha(1 - readerBarAlpha),
) { ) {
Log.i("RLog", "AppNavigationBar: ${readerBarAlpha}, ${1f - readerBarAlpha}") Log.i("RLog", "AppNavigationBar: ${readerBarAlpha}, ${1f - readerBarAlpha}")
FilterBar( // FilterBar(
// modifier = modifier,
// filter = filter,
// onSelected = filterOnClick,
// )
FilterBar2(
modifier = modifier, modifier = modifier,
filter = filter, filter = filter,
onSelected = filterOnClick, onSelected = filterOnClick,

View File

@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyListState
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.data.account.Account import me.ash.reader.data.account.Account
@ -67,6 +68,7 @@ class FeedsViewModel @Inject constructor(
rssRepository.get().pullFeeds(), rssRepository.get().pullFeeds(),
rssRepository.get().pullImportant(isStarred, isUnread), rssRepository.get().pullImportant(isStarred, isUnread),
) { groupWithFeedList, importantList -> ) { groupWithFeedList, importantList ->
Log.i("RLog", "thread:combine ${Thread.currentThread().name}")
val groupImportantMap = mutableMapOf<String, Int>() val groupImportantMap = mutableMapOf<String, Int>()
val feedImportantMap = mutableMapOf<String, Int>() val feedImportantMap = mutableMapOf<String, Int>()
importantList.groupBy { it.groupId }.forEach { (i, list) -> importantList.groupBy { it.groupId }.forEach { (i, list) ->
@ -101,6 +103,8 @@ class FeedsViewModel @Inject constructor(
}.onStart { }.onStart {
}.onEach { groupWithFeedList -> }.onEach { groupWithFeedList ->
Log.i("RLog", "thread:onEach ${Thread.currentThread().name}")
_viewState.update { _viewState.update {
it.copy( it.copy(
filter = when { filter = when {
@ -116,7 +120,7 @@ class FeedsViewModel @Inject constructor(
} }
}.catch { }.catch {
Log.e("RLog", "catch in articleRepository.pullFeeds(): $this") Log.e("RLog", "catch in articleRepository.pullFeeds(): $this")
}.collect() }.flowOn(Dispatchers.Default).collect()
} }
private fun scrollToItem(index: Int) { private fun scrollToItem(index: Int) {

View File

@ -19,12 +19,11 @@ import me.ash.reader.ui.page.home.read.ReadViewModel
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
fun LazyListScope.generateArticleList( fun LazyListScope.generateArticleList(
context: Context, context: Context,
pagingItems: LazyPagingItems<ArticleWithFeed>?, pagingItems: LazyPagingItems<ArticleWithFeed>,
readViewModel: ReadViewModel, readViewModel: ReadViewModel,
homeViewModel: HomeViewModel, homeViewModel: HomeViewModel,
scope: CoroutineScope scope: CoroutineScope
) { ) {
pagingItems ?: return
var lastItemDay: String? = null var lastItemDay: String? = null
for (itemIndex in 0 until pagingItems.itemCount) { for (itemIndex in 0 until pagingItems.itemCount) {
val currentItem = pagingItems.peek(itemIndex) ?: continue val currentItem = pagingItems.peek(itemIndex) ?: continue

View File

@ -22,7 +22,6 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.flow.collect
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.extension.collectAsStateValue
import me.ash.reader.ui.extension.getName import me.ash.reader.ui.extension.getName
@ -46,7 +45,7 @@ fun FlowPage(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val viewState = viewModel.viewState.collectAsStateValue() val viewState = viewModel.viewState.collectAsStateValue()
val filterState = homeViewModel.filterState.collectAsStateValue() val filterState = homeViewModel.filterState.collectAsStateValue()
val pagingItems = viewState.pagingData?.collectAsLazyPagingItems() val pagingItems = viewState.pagingData.collectAsLazyPagingItems()
LaunchedEffect(homeViewModel.filterState) { LaunchedEffect(homeViewModel.filterState) {
homeViewModel.filterState.collect { state -> homeViewModel.filterState.collect { state ->

View File

@ -1,5 +1,6 @@
package me.ash.reader.ui.page.home.flow package me.ash.reader.ui.page.home.flow
import android.util.Log
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@ -8,6 +9,7 @@ import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.article.ArticleWithFeed
@ -53,13 +55,14 @@ class FlowViewModel @Inject constructor(
_viewState.update { _viewState.update {
it.copy( it.copy(
pagingData = Pager(PagingConfig(pageSize = 10)) { pagingData = Pager(PagingConfig(pageSize = 10)) {
Log.i("RLog", "thread:Pager ${Thread.currentThread().name}")
rssRepository.get().pullArticles( rssRepository.get().pullArticles(
groupId = filterState.group?.id, groupId = filterState.group?.id,
feedId = filterState.feed?.id, feedId = filterState.feed?.id,
isStarred = filterState.filter.isStarred(), isStarred = filterState.filter.isStarred(),
isUnread = filterState.filter.isUnread(), isUnread = filterState.filter.isUnread(),
) )
}.flow.cachedIn(viewModelScope) }.flow.flowOn(Dispatchers.IO).cachedIn(viewModelScope)
) )
} }
} }
@ -81,7 +84,7 @@ data class ArticleViewState(
val filterImportant: Int = 0, val filterImportant: Int = 0,
val listState: LazyListState = LazyListState(), val listState: LazyListState = LazyListState(),
val isRefreshing: Boolean = false, val isRefreshing: Boolean = false,
val pagingData: Flow<PagingData<ArticleWithFeed>>? = null, val pagingData: Flow<PagingData<ArticleWithFeed>> = emptyFlow(),
val syncWorkInfo: String = "", val syncWorkInfo: String = "",
) )