Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-30 19:27:21 +01:00
parent 75e81283f8
commit faaa2aad8f
28 changed files with 795 additions and 316 deletions

View file

@ -45,8 +45,8 @@ internal class DefaultNewsRepository(
return updateViewedStatusForNewsBatch(newsBatchFlow, context.coroutineScope)
}
override suspend fun getNews(config: NewsListConfig, limit: Int): List<ShortArticle> {
return withContext(dispatchers.io) {
override fun getNews(config: NewsListConfig, limit: Int): Flow<List<ShortArticle>> {
return flow {
val response = newsApi.getNews(
page = FIRST_PAGE,
limit = limit,
@ -56,25 +56,16 @@ internal class DefaultNewsRepository(
categoryIds = config.categoryIds.takeIf { it.isNotEmpty() },
).getOrThrow()
val articles = response.items.map { it.toDomainShortArticle() }
val viewedFlags = newsViewedStore.getSync()
articles.map { article ->
val isViewed = viewedFlags[article.id] == true
article.copy(viewed = isViewed)
val shortArticles = response.items.map { it.toDomainShortArticle() }
emit(shortArticles)
}
.flowOn(dispatchers.io)
.combine(newsViewedStore.getAll()) { articlesToUpdate, viewedFlags ->
articlesToUpdate.map { article ->
val isViewed = viewedFlags[article.id] == true
article.copy(viewed = isViewed)
}.sortedBy { it.viewed }
}
}
}
override suspend fun getDetailedArticle(newsId: Int, language: String?): DetailedArticle {
val cached = newsDetailsStore.getSyncOrNull(newsId)
if (cached != null) return cached
fetchDetailedArticlesInternal(newsIds = listOf(newsId), language = language)
return requireNotNull(newsDetailsStore.getSyncOrNull(newsId)) {
"Unable to load detailed article with id=$newsId"
}
}
override fun observeDetailedArticles(): Flow<Map<Int, DetailedArticle>> {
@ -98,10 +89,11 @@ internal class DefaultNewsRepository(
) { trendingNews, viewedFlags ->
when (trendingNews) {
is TrendingNews.Data -> {
val articlesWithViewedFlags = trendingNews.articles.map { article ->
val isViewed = viewedFlags[article.id] == true
article.copy(viewed = isViewed)
}
val articlesWithViewedFlags = trendingNews.articles
.map { article ->
article.copy(viewed = viewedFlags[article.id] == true)
}
.sortedBy { it.viewed }
TrendingNews.Data(articlesWithViewedFlags)
}
is TrendingNews.Error -> trendingNews
@ -128,32 +120,11 @@ internal class DefaultNewsRepository(
newsBatchFlow: NewsListBatchFlow,
scope: CoroutineScope,
): NewsListBatchFlow {
return object : NewsListBatchFlow {
override val state: StateFlow<BatchListState<Int, List<ShortArticle>>> =
combine(
newsBatchFlow.state,
newsViewedStore.getAll(),
) { batchListState, viewedFlags ->
val updatedBatches = batchListState.data.map { batch ->
val updatedArticles = batch.data.map { article ->
val isViewed = viewedFlags[article.id] == true
article.copy(viewed = isViewed)
}
Batch(key = batch.key, data = updatedArticles)
}
BatchListState(
data = updatedBatches,
status = batchListState.status,
)
}.stateIn(
scope = scope,
started = SharingStarted.Eagerly,
initialValue = BatchListState(emptyList(), newsBatchFlow.state.value.status),
)
override val updateResults: SharedFlow<Pair<Nothing, BatchUpdateResult<Int, List<ShortArticle>>>> =
newsBatchFlow.updateResults
}
return NewsBatchFlowWithViewedStatus(
upstream = newsBatchFlow,
newsViewedStore = newsViewedStore,
scope = scope,
)
}
private suspend fun fetchDetailedArticlesInternal(newsIds: Collection<Int>, language: String?) =
@ -340,6 +311,37 @@ internal class DefaultNewsRepository(
val params: NewsListConfig,
)
private class NewsBatchFlowWithViewedStatus(
private val upstream: NewsListBatchFlow,
newsViewedStore: NewsViewedStore,
scope: CoroutineScope,
) : NewsListBatchFlow {
override val state: StateFlow<BatchListState<Int, List<ShortArticle>>> = combine(
upstream.state,
newsViewedStore.getAll(),
) { batchListState, viewedFlags ->
val updatedBatches = batchListState.data.map { batch ->
val updatedArticles = batch.data.map { article ->
val isViewed = viewedFlags[article.id] == true
article.copy(viewed = isViewed)
}
Batch(key = batch.key, data = updatedArticles)
}
BatchListState(
data = updatedBatches,
status = batchListState.status,
)
}.stateIn(
scope = scope,
started = SharingStarted.Eagerly,
initialValue = BatchListState(emptyList(), upstream.state.value.status),
)
override val updateResults: SharedFlow<Pair<Nothing, BatchUpdateResult<Int, List<ShortArticle>>>>
get() = upstream.updateResults
}
private companion object {
private const val INITIAL_BATCH_KEY = 0
private const val FIRST_PAGE = 1