Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ class MainActivity : BaseThemeActivity() {
backStack.add(feedSource.toEditFeed())
},
onFeedSuggestionsClick = { backStack.add(FeedSuggestions) },
onNavigateToNextFeed = { homeViewModel.onNavigateToNextFeed() },
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowWidthSizeClass
import com.prof18.feedflow.android.BrowserManager
import com.prof18.feedflow.android.categoryselection.EditCategorySheet
import com.prof18.feedflow.android.openShareSheet
Expand All @@ -29,11 +30,15 @@ import com.prof18.feedflow.core.model.LinkOpeningPreference
import com.prof18.feedflow.core.model.shouldOpenInBrowser
import com.prof18.feedflow.shared.presentation.ChangeFeedCategoryViewModel
import com.prof18.feedflow.shared.presentation.HomeViewModel
import com.prof18.feedflow.shared.presentation.model.NextFeedPreviewState
import com.prof18.feedflow.shared.presentation.model.NextFeedPreviewState.NextFeedPreviewDisabledState
import com.prof18.feedflow.shared.presentation.model.NextFeedPreviewState.NextFeedPreviewEnabledState
import com.prof18.feedflow.shared.presentation.model.UIErrorState
import com.prof18.feedflow.shared.ui.home.AdaptiveHomeView
import com.prof18.feedflow.shared.ui.home.FeedListActions
import com.prof18.feedflow.shared.ui.home.FeedManagementActions
import com.prof18.feedflow.shared.ui.home.HomeDisplayState
import com.prof18.feedflow.shared.ui.home.NextFeedDisplayState
import com.prof18.feedflow.shared.ui.home.ShareBehavior
import com.prof18.feedflow.shared.ui.home.WindowSizeClass
import com.prof18.feedflow.shared.ui.home.components.LoadingOperationDialog
Expand All @@ -49,8 +54,9 @@ internal fun HomeScreen(
onSearchClick: () -> Unit,
onAccountsClick: () -> Unit,
onEditFeedClick: (FeedSource) -> Unit,
onImportExportClick: () -> Unit = {},
onFeedSuggestionsClick: () -> Unit,
onNavigateToNextFeed: () -> Unit,
onImportExportClick: () -> Unit = {},
) {
val browserManager = koinInject<BrowserManager>()
val changeFeedCategoryViewModel: ChangeFeedCategoryViewModel = koinInject()
Expand All @@ -59,6 +65,7 @@ internal fun HomeScreen(
val feedState by homeViewModel.feedState.collectAsStateWithLifecycle()
val navDrawerState by homeViewModel.navDrawerState.collectAsStateWithLifecycle()
val currentFeedFilter by homeViewModel.currentFeedFilter.collectAsStateWithLifecycle()
val nextFeedPreviewState: NextFeedPreviewState by homeViewModel.nextFeedPreviewState.collectAsStateWithLifecycle()
val unReadCount by homeViewModel.unreadCountFlow.collectAsStateWithLifecycle(initialValue = 0)
val feedFontSizes by homeViewModel.feedFontSizeState.collectAsStateWithLifecycle()
val swipeActions by homeViewModel.swipeActions.collectAsStateWithLifecycle()
Expand Down Expand Up @@ -130,6 +137,7 @@ internal fun HomeScreen(
swipeActions = swipeActions,
feedLayout = feedLayout,
isSyncUploadRequired = isSyncUploadRequired,
nextFeedDisplayState = nextFeedPreviewState.asDisplayState(),
)

val feedListActions = FeedListActions(
Expand Down Expand Up @@ -168,8 +176,8 @@ internal fun HomeScreen(

val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
val adaptiveWindowSizeClass = when (windowSizeClass.windowWidthSizeClass) {
androidx.window.core.layout.WindowWidthSizeClass.COMPACT -> WindowSizeClass.Compact
androidx.window.core.layout.WindowWidthSizeClass.MEDIUM -> WindowSizeClass.Medium
WindowWidthSizeClass.COMPACT -> WindowSizeClass.Compact
WindowWidthSizeClass.MEDIUM -> WindowSizeClass.Medium
else -> WindowSizeClass.Expanded
}

Expand Down Expand Up @@ -208,6 +216,7 @@ internal fun HomeScreen(
onEmptyStateClick = {
showNoFeedsBottomSheet = true
},
onNavigateToNextFeed = onNavigateToNextFeed,
)

if (showChangeCategorySheet) {
Expand Down Expand Up @@ -278,3 +287,8 @@ private fun openUrl(
}
}
}

fun NextFeedPreviewState.asDisplayState(): NextFeedDisplayState = when (this) {
is NextFeedPreviewDisabledState -> NextFeedDisplayState.NextFeedDisplayDisabledState
is NextFeedPreviewEnabledState -> NextFeedDisplayState.NextFeedDisplayEnabledState(this.title)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.prof18.feedflow.shared.presentation.model.UIErrorState
import com.prof18.feedflow.shared.ui.home.FeedListActions
import com.prof18.feedflow.shared.ui.home.FeedManagementActions
import com.prof18.feedflow.shared.ui.home.HomeDisplayState
import com.prof18.feedflow.shared.ui.home.NextFeedDisplayState.NextFeedDisplayDisabledState
import com.prof18.feedflow.shared.ui.home.ShareBehavior
import com.prof18.feedflow.shared.ui.home.components.LoadingOperationDialog
import com.prof18.feedflow.shared.ui.utils.LocalFeedFlowStrings
Expand Down Expand Up @@ -132,6 +133,7 @@ internal fun HomeScreen(
currentFeedFilter = currentFeedFilter,
swipeActions = swipeActions,
feedLayout = feedLayout,
nextFeedDisplayState = NextFeedDisplayDisabledState,
)

val openReaderArticle: (FeedItemUrlInfo) -> Unit = { article ->
Expand Down
1 change: 1 addition & 0 deletions i18n/src/commonMain/resources/locale/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@
<string name="scroll_to_top_button_content_description">Scroll to top</string>
<string name="previous_article">Previous article</string>
<string name="next_article">Next article</string>
<string name="next">Next</string>
<string name="settings_theme">Theme</string>
<string name="settings_theme_system">System</string>
<string name="settings_theme_light">Light</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import com.prof18.feedflow.shared.presentation.FeedSourceListViewModel
import com.prof18.feedflow.shared.presentation.FeedSuggestionsViewModel
import com.prof18.feedflow.shared.presentation.FeedbinSyncViewModel
import com.prof18.feedflow.shared.presentation.FreshRssSyncViewModel
import com.prof18.feedflow.shared.presentation.GetNextFeedFilterOrNullUseCase
import com.prof18.feedflow.shared.presentation.HomeViewModel
import com.prof18.feedflow.shared.presentation.ImportExportViewModel
import com.prof18.feedflow.shared.presentation.MainSettingsViewModel
Expand Down Expand Up @@ -197,6 +198,7 @@ private fun getCoreModule(appConfig: AppConfig) = module {
feedCategoryRepository = get(),
feedStateRepository = get(),
feedFetcherRepository = get(),
getNextFeedFilterOrNullUseCase = get(),
)
}

Expand Down Expand Up @@ -577,6 +579,12 @@ private fun getCoreModule(appConfig: AppConfig) = module {
backgroundSyncScheduler = get(),
)
}

single {
GetNextFeedFilterOrNullUseCase(
feedSourcesRepository = get(),
)
}
}

internal expect fun platformLogWriters(): List<LogWriter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ internal class FeedSourcesRepository(
fun getFeedSources(): Flow<List<FeedSource>> =
databaseHelper.getFeedSourcesFlow()

fun getFeedSourcesWithUnreadCount(): Flow<List<FeedSourceWithUnreadCount>> =
databaseHelper.getFeedSourcesWithUnreadCountFlow()

suspend fun deleteFeed(feedSource: FeedSource) {
when (accountsRepository.getCurrentSyncAccount()) {
SyncAccounts.FRESH_RSS, SyncAccounts.MINIFLUX, SyncAccounts.BAZQUX -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.prof18.feedflow.shared.presentation

import com.prof18.feedflow.core.model.FeedFilter
import com.prof18.feedflow.shared.domain.feed.FeedSourcesRepository
import kotlinx.coroutines.flow.first

class GetNextFeedFilterOrNullUseCase internal constructor(
Comment thread
paolorotolo marked this conversation as resolved.
private val feedSourcesRepository: FeedSourcesRepository,
) {

suspend operator fun invoke(
currentFeedFilter: FeedFilter,
): FeedFilter? {
when (currentFeedFilter) {
is FeedFilter.Category -> {
val unreadCategoryList = feedSourcesRepository
.observeFeedSourcesByCategoryWithUnreadCount()
.first()
.mapValues { source -> source.value.sumOf { it.unreadCount } }
.filter { it.value > 0 }
.keys
.filterNotNull()

val currentCategoryIndex = unreadCategoryList
.indexOfFirst { it.id == currentFeedFilter.feedCategory.id }

return FeedFilter.Category(
feedCategory = unreadCategoryList
.drop(currentCategoryIndex + 1)
.firstOrNull()
?: return null,
)
}
is FeedFilter.Source -> {
val feedSources = feedSourcesRepository.getFeedSourcesWithUnreadCount().first()
.filter {
it.feedSource.category?.id == currentFeedFilter.feedSource.category?.id
}

val currentSourceIndex = feedSources.indexOfFirst {
it.feedSource.id == currentFeedFilter.feedSource.id
}

if (currentSourceIndex == -1) return null

val nextUnreadSource = feedSources
.drop(currentSourceIndex + 1)
.firstOrNull { it.unreadCount > 0 }

return FeedFilter.Source(
feedSource = nextUnreadSource?.feedSource ?: return null,
)
}
else -> return null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.prof18.feedflow.shared.domain.feedsync.FeedSyncRepository
import com.prof18.feedflow.shared.presentation.model.DatabaseError
import com.prof18.feedflow.shared.presentation.model.DeleteFeedSourceError
import com.prof18.feedflow.shared.presentation.model.FeedErrorState
import com.prof18.feedflow.shared.presentation.model.NextFeedPreviewState
import com.prof18.feedflow.shared.presentation.model.SyncError
import com.prof18.feedflow.shared.presentation.model.UIErrorState
import kotlinx.collections.immutable.ImmutableList
Expand Down Expand Up @@ -57,6 +58,7 @@ class HomeViewModel internal constructor(
private val feedCategoryRepository: FeedCategoryRepository,
private val feedStateRepository: FeedStateRepository,
private val feedFetcherRepository: FeedFetcherRepository,
private val getNextFeedFilterOrNullUseCase: GetNextFeedFilterOrNullUseCase,
) : ViewModel() {

// Loading
Expand All @@ -80,6 +82,11 @@ class HomeViewModel internal constructor(
private val refreshTriggerMutableState = MutableStateFlow(0)
val refreshTriggerState: StateFlow<Int> = refreshTriggerMutableState.asStateFlow()

private val nextFeedPreviewMutableState: MutableStateFlow<NextFeedPreviewState> = MutableStateFlow(
NextFeedPreviewState.NextFeedPreviewDisabledState,
)
val nextFeedPreviewState: StateFlow<NextFeedPreviewState> = nextFeedPreviewMutableState.asStateFlow()

private var lastUpdateIndex = 0
private var hasTriggeredAppLaunch = false

Expand Down Expand Up @@ -332,6 +339,28 @@ class HomeViewModel internal constructor(
feedStateRepository.updateFeedFilter(selectedFeedFilter)
lastUpdateIndex = 0
}

updateNextFeedPreview(selectedFeedFilter)
}

fun updateNextFeedPreview(currentFeedFilter: FeedFilter) {
viewModelScope.launch {
nextFeedPreviewMutableState.update {
val nextFeed = getNextFeedFilterOrNullUseCase(currentFeedFilter)

when (nextFeed) {
is FeedFilter.Category -> NextFeedPreviewState.NextFeedPreviewEnabledState(
feedFilter = nextFeed,
title = nextFeed.feedCategory.title,
)
is FeedFilter.Source -> NextFeedPreviewState.NextFeedPreviewEnabledState(
feedFilter = nextFeed,
title = nextFeed.feedSource.title,
)
else -> NextFeedPreviewState.NextFeedPreviewDisabledState
}
}
}
}

fun updateReadStatus(feedItemId: FeedItemId, read: Boolean) {
Expand Down Expand Up @@ -385,5 +414,14 @@ class HomeViewModel internal constructor(
}
}

fun onNavigateToNextFeed() {
when (val nextFeed = nextFeedPreviewState.value) {
is NextFeedPreviewState.NextFeedPreviewEnabledState -> {
onFeedFilterSelected(selectedFeedFilter = nextFeed.feedFilter)
}
is NextFeedPreviewState.NextFeedPreviewDisabledState -> {}
}
}

fun getCurrentThemeMode() = settingsRepository.getThemeMode()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.prof18.feedflow.shared.presentation.model

import com.prof18.feedflow.core.model.FeedFilter

sealed class NextFeedPreviewState {
data class NextFeedPreviewEnabledState(
val title: String,
val feedFilter: FeedFilter,
) : NextFeedPreviewState()

data object NextFeedPreviewDisabledState : NextFeedPreviewState()
}
Loading
Loading