Skip to content

Commit

Permalink
Load combined sources (feed & feed group) in feeds bottom sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
msasikanth committed Apr 17, 2024
1 parent 2e03f8d commit 7ebc236
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.text.input.TextFieldValue
import androidx.paging.PagingData
import androidx.paging.insertSeparators
import app.cash.paging.cachedIn
import app.cash.paging.createPager
import app.cash.paging.createPagingConfig
import app.cash.paging.map
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.essenty.instancekeeper.InstanceKeeper
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.arkivanov.essenty.lifecycle.doOnCreate
import dev.sasikanth.rss.reader.core.model.local.Feed
import dev.sasikanth.rss.reader.core.model.local.Source
import dev.sasikanth.rss.reader.core.model.local.SourceType
import dev.sasikanth.rss.reader.feeds.ui.FeedsViewMode
import dev.sasikanth.rss.reader.home.ui.PostsType
import dev.sasikanth.rss.reader.repository.FeedsOrderBy
Expand All @@ -45,18 +48,18 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
Expand Down Expand Up @@ -264,10 +267,9 @@ class FeedsPresenter(
}

private fun init() {
observeSources()
observePreferences()
observeShowUnreadCountPreference()
observeFeedsForCollapsedSheet()
observeFeedsForExpandedSheet()
observeSearchQuery()
}

Expand Down Expand Up @@ -306,13 +308,15 @@ class FeedsPresenter(
.launchIn(coroutineScope)
}

private fun observeFeedsForExpandedSheet() {
settingsRepository.postsType
.onEach { postsType ->
val postsAfter = postsAfterInstantFromPostsType(postsType)
val pinnedFeeds = pinnedFeedsPager(postsAfter = postsAfter).cachedIn(coroutineScope)
private fun observeSources() {
observableActiveSource.activeSource
.onEach { activeSource -> _state.update { it.copy(activeSource = activeSource) } }
.launchIn(coroutineScope)

_state.update { it.copy(pinnedFeeds = pinnedFeeds) }
rssRepository
.numberOfFeeds()
.onEach { numberOfFeeds ->
_state.update { it.copy(numberOfFeeds = numberOfFeeds.toInt()) }
}
.launchIn(coroutineScope)

Expand All @@ -324,49 +328,22 @@ class FeedsPresenter(
.onEach { (postsType, feedsSortOrder) ->
val postsAfter = postsAfterInstantFromPostsType(postsType)

val feeds =
feedsPager(
postsAfter = postsAfter,
feedsSortOrder = feedsSortOrder,
)
.cachedIn(coroutineScope)

_state.update { it.copy(feedsInExpandedView = feeds) }
}
.launchIn(coroutineScope)

val feedGroups =
createPager(config = createPagingConfig(20)) { rssRepository.feedGroups() }
.flow
.cachedIn(coroutineScope)

val pinnedFeedGroups =
createPager(config = createPagingConfig(20)) { rssRepository.pinnedFeedGroups() }
.flow
.cachedIn(coroutineScope)

_state.update { it.copy(feedGroups = feedGroups, pinnedFeedGroups = pinnedFeedGroups) }
}

private fun observeFeedsForCollapsedSheet() {
val feeds =
settingsRepository.postsType.distinctUntilChanged().flatMapLatest { postsType ->
val postsAfter = postsAfterInstantFromPostsType(postsType)

feedsPager(postsAfter, FeedsOrderBy.Pinned).cachedIn(coroutineScope)
}
val pinnedSources = pinnedSources(postsAfter = postsAfter).cachedIn(coroutineScope)
val sources =
sources(
postsAfter = postsAfter,
feedsSortOrder = feedsSortOrder,
)
val sourcesWithSeparator = addSourcesSeparator(sources)

observableActiveSource.activeSource
.distinctUntilChanged()
.onEach { selectedFeed ->
_state.update { it.copy(feedsInBottomBar = feeds, activeSource = selectedFeed) }
_state.update { it.copy(pinnedSources = pinnedSources, sources = sourcesWithSeparator) }
}
.launchIn(coroutineScope)
}

private fun pinnedFeedsPager(postsAfter: Instant) =
private fun pinnedSources(postsAfter: Instant) =
createPager(config = createPagingConfig(pageSize = 20)) {
rssRepository.pinnedFeeds(postsAfter = postsAfter)
rssRepository.pinnedSources(postsAfter = postsAfter)
}
.flow

Expand All @@ -376,9 +353,9 @@ class FeedsPresenter(
}
.flow

private fun feedsPager(postsAfter: Instant, feedsSortOrder: FeedsOrderBy) =
private fun sources(postsAfter: Instant, feedsSortOrder: FeedsOrderBy) =
createPager(config = createPagingConfig(pageSize = 20)) {
rssRepository.allFeeds(postsAfter = postsAfter, orderBy = feedsSortOrder)
rssRepository.sources(postsAfter = postsAfter, orderBy = feedsSortOrder)
}
.flow

Expand All @@ -388,6 +365,26 @@ class FeedsPresenter(
.launchIn(coroutineScope)
}

private fun addSourcesSeparator(
sources: Flow<PagingData<Source>>
): Flow<PagingData<SourceListItem>> {
return sources.mapLatest {
it
.map { source -> SourceListItem.SourceItem(source) }
.insertSeparators { before, after ->
when {
before?.source?.sourceType == SourceType.FeedGroup &&
after?.source?.sourceType == SourceType.Feed -> {
SourceListItem.Separator
}
else -> {
null
}
}
}
}
}

private fun postsAfterInstantFromPostsType(postsType: PostsType) =
when (postsType) {
PostsType.ALL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package dev.sasikanth.rss.reader.feeds
import androidx.compose.runtime.Immutable
import androidx.paging.PagingData
import dev.sasikanth.rss.reader.core.model.local.Feed
import dev.sasikanth.rss.reader.core.model.local.FeedGroup
import dev.sasikanth.rss.reader.core.model.local.Source
import dev.sasikanth.rss.reader.feeds.ui.FeedsViewMode
import dev.sasikanth.rss.reader.repository.FeedsOrderBy
Expand All @@ -27,18 +26,16 @@ import kotlinx.coroutines.flow.emptyFlow

@Immutable
internal data class FeedsState(
val feedsInBottomBar: Flow<PagingData<Feed>>,
val feedsInExpandedView: Flow<PagingData<Feed>>,
val pinnedFeeds: Flow<PagingData<Feed>>,
val pinnedSources: Flow<PagingData<Source>>,
val sources: Flow<PagingData<SourceListItem>>,
val feedsSearchResults: Flow<PagingData<Feed>>,
val feedGroups: Flow<PagingData<FeedGroup>>,
val pinnedFeedGroups: Flow<PagingData<FeedGroup>>,
val activeSource: Source?,
val canShowUnreadPostsCount: Boolean,
val feedsViewMode: FeedsViewMode,
val feedsSortOrder: FeedsOrderBy,
val isPinnedSectionExpanded: Boolean,
val selectedSources: Set<Source>,
val numberOfFeeds: Int,
) {

val isInMultiSelectMode: Boolean
Expand All @@ -48,18 +45,16 @@ internal data class FeedsState(

val DEFAULT =
FeedsState(
feedsInBottomBar = emptyFlow(),
feedsInExpandedView = emptyFlow(),
pinnedFeeds = emptyFlow(),
feedsSearchResults = emptyFlow(),
feedGroups = emptyFlow(),
pinnedFeedGroups = emptyFlow(),
pinnedSources = emptyFlow(),
sources = emptyFlow(),
activeSource = null,
canShowUnreadPostsCount = false,
feedsViewMode = FeedsViewMode.List,
feedsSortOrder = FeedsOrderBy.Latest,
isPinnedSectionExpanded = true,
selectedSources = emptySet()
selectedSources = emptySet(),
numberOfFeeds = 0
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.feeds

import dev.sasikanth.rss.reader.core.model.local.Source

sealed interface SourceListItem {

data class SourceItem(val source: Source) : SourceListItem

data object Separator : SourceListItem
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ import dev.sasikanth.rss.reader.ui.AppTheme
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun BottomSheetCollapsedContent(
feeds: LazyPagingItems<Feed>,
feedGroups: LazyPagingItems<FeedGroup>,
pinnedSources: LazyPagingItems<Source>,
activeSource: Source?,
canShowUnreadPostsCount: Boolean,
onSourceClick: (Source) -> Unit,
Expand Down Expand Up @@ -77,28 +76,28 @@ internal fun BottomSheetCollapsedContent(
)
}

items(feedGroups.itemCount) { index ->
val feedGroup = feedGroups[index]
if (feedGroup != null) {
FeedGroupBottomBarItem(
feedGroup = feedGroup,
selected = activeSource?.id == feedGroup.id,
onClick = { onSourceClick(feedGroup) }
)
}
}

items(feeds.itemCount) { index ->
val feed = feeds[index]
if (feed != null) {
FeedBottomBarItem(
text = feed.name.uppercase(),
badgeCount = feed.numberOfUnreadPosts,
iconUrl = feed.icon,
canShowUnreadPostsCount = canShowUnreadPostsCount,
selected = activeSource?.id == feed.id,
onClick = { onSourceClick(feed) }
)
items(pinnedSources.itemCount) { index ->
val source = pinnedSources[index]
if (source != null) {
when (source) {
is FeedGroup -> {
FeedGroupBottomBarItem(
feedGroup = source,
selected = activeSource?.id == source.id,
onClick = { onSourceClick(source) }
)
}
is Feed -> {
FeedBottomBarItem(
text = source.name.uppercase(),
badgeCount = source.numberOfUnreadPosts,
iconUrl = source.icon,
canShowUnreadPostsCount = canShowUnreadPostsCount,
selected = activeSource?.id == source.id,
onClick = { onSourceClick(source) }
)
}
}
}
}
}
Expand Down
Loading

0 comments on commit 7ebc236

Please sign in to comment.