diff --git a/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/downloads/DownloadsViewModel.kt b/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/downloads/DownloadsViewModel.kt index 4050464c..144b00ca 100644 --- a/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/downloads/DownloadsViewModel.kt +++ b/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/downloads/DownloadsViewModel.kt @@ -14,6 +14,8 @@ import app.cash.molecule.launchMolecule import com.mr3y.podcaster.core.data.PodcastsRepository import com.mr3y.podcaster.ui.presenter.BaseMoleculeViewModel import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -37,21 +39,12 @@ internal fun DownloadsPresenter( var isLoading by remember { mutableStateOf(true) } val downloads by repository.getDownloads().collectAsState(initial = emptyList()) - LaunchedEffect(Unit) { - launch { - // if the user has no downloads - repository.hasDownloads() - .filter { hasDownloads -> !hasDownloads } - .collect { - isLoading = false - } - } - launch { - snapshotFlow { downloads } - .drop(1) - .collect { - isLoading = false - } + LaunchedEffect(downloads) { + if (downloads.isNotEmpty()) { + isLoading = false + } else { + delay(1000) + isLoading = false } } diff --git a/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsViewModel.kt b/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsViewModel.kt index ecd66c9d..c5612ec5 100644 --- a/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsViewModel.kt +++ b/app/src/main/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsViewModel.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import androidx.compose.runtime.snapshots.Snapshot import app.cash.molecule.RecompositionMode import app.cash.molecule.launchMolecule import com.mr3y.podcaster.core.data.PodcastsRepository @@ -17,7 +18,9 @@ import com.mr3y.podcaster.ui.presenter.RefreshResult import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -55,30 +58,21 @@ internal fun SubscriptionsPresenter( val queueEpisodesIds by repository.getQueueEpisodesIds().collectAsState(initial = emptyList()) var refreshResult: RefreshResult? by remember { mutableStateOf(null) } - LaunchedEffect(Unit) { - launch { - // if the user has no subscriptions yet - repository.hasSubscriptions() - .filter { isSubscribedToAnyPodcast -> !isSubscribedToAnyPodcast } - .collect { - isSubscriptionsLoading = false - isEpisodesLoading = false - } + LaunchedEffect(podcasts, episodes) { + if (podcasts.isNotEmpty()) { + isSubscriptionsLoading = false } - launch { - snapshotFlow { podcasts } - .drop(1) // Ignore initial value - .collect { - isSubscriptionsLoading = false - } + + if (episodes.isNotEmpty()) { + isEpisodesLoading = false } - launch { - snapshotFlow { episodes } - .drop(1) // Ignore initial value - .collect { - isEpisodesLoading = false - } + if (podcasts.isEmpty() || episodes.isEmpty()) { + delay(1000) + Snapshot.withMutableSnapshot { + isSubscriptionsLoading = false + isEpisodesLoading = false + } } } diff --git a/app/src/test/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsPresenterTest.kt b/app/src/test/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsPresenterTest.kt index 7a899460..8af82676 100644 --- a/app/src/test/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsPresenterTest.kt +++ b/app/src/test/kotlin/com/mr3y/podcaster/ui/presenter/subscriptions/SubscriptionsPresenterTest.kt @@ -50,9 +50,6 @@ class SubscriptionsPresenterTest : BasePresenterTest() { assertThat(currentState.episodes).isEmpty() currentState = awaitItem() assertThat(currentState.subscriptions).isEqualTo(listOf(Podcasts[0])) - // each episode addition triggers separate state update, and we added 2 episodes - assertThat(currentState.episodes).hasSize(1) - currentState = awaitItem() assertThat(currentState.episodes).hasSize(2) expectNoEvents() diff --git a/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/PodcastsRepository.kt b/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/PodcastsRepository.kt index 08e54807..b7bc05a8 100644 --- a/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/PodcastsRepository.kt +++ b/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/PodcastsRepository.kt @@ -30,9 +30,9 @@ interface PodcastsRepository { fun isPodcastFromSubscriptionsNonObservable(podcastId: Long): Boolean - fun hasSubscriptions(): Flow + fun countSubscriptions(): Flow - fun hasDownloads(): Flow + fun countDownloads(): Flow suspend fun getEpisode(episodeId: Long, podcastArtworkUrl: String, forceRefresh: Boolean): Episode? diff --git a/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/internal/DefaultPodcastsRepository.kt b/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/internal/DefaultPodcastsRepository.kt index ef70316b..bdae3b55 100644 --- a/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/internal/DefaultPodcastsRepository.kt +++ b/core/data/src/main/kotlin/com/mr3y/podcaster/core/data/internal/DefaultPodcastsRepository.kt @@ -73,9 +73,9 @@ class DefaultPodcastsRepository @Inject constructor( return podcastsDao.isPodcastAvailableNonObservable(podcastId) } - override fun hasSubscriptions(): Flow = podcastsDao.hasPodcasts() + override fun countSubscriptions(): Flow = podcastsDao.countPodcasts() - override fun hasDownloads(): Flow = podcastsDao.hasDownloads() + override fun countDownloads(): Flow = podcastsDao.countDownloads() override suspend fun getEpisode(episodeId: Long, podcastArtworkUrl: String, forceRefresh: Boolean): Episode? { suspend fun fetchFromNetworkAndRefresh(): Episode? { diff --git a/core/database/src/main/kotlin/com/mr3y/podcaster/core/local/dao/PodcastsDao.kt b/core/database/src/main/kotlin/com/mr3y/podcaster/core/local/dao/PodcastsDao.kt index 9d4d74f4..2b37f02e 100644 --- a/core/database/src/main/kotlin/com/mr3y/podcaster/core/local/dao/PodcastsDao.kt +++ b/core/database/src/main/kotlin/com/mr3y/podcaster/core/local/dao/PodcastsDao.kt @@ -2,6 +2,7 @@ package com.mr3y.podcaster.core.local.dao import app.cash.sqldelight.coroutines.asFlow import app.cash.sqldelight.coroutines.mapToList +import app.cash.sqldelight.coroutines.mapToOne import app.cash.sqldelight.coroutines.mapToOneOrNull import com.mr3y.podcaster.CurrentlyPlayingEntity import com.mr3y.podcaster.PodcasterDatabase @@ -35,9 +36,9 @@ interface PodcastsDao { fun isPodcastAvailable(podcastId: Long): Flow - fun hasPodcasts(): Flow + fun countPodcasts(): Flow - fun hasDownloads(): Flow + fun countDownloads(): Flow fun isPodcastAvailableNonObservable(podcastId: Long): Boolean @@ -145,18 +146,12 @@ class DefaultPodcastsDao @Inject constructor( .map { it == 1L } } - override fun hasPodcasts(): Flow { - return database.podcastEntityQueries.countPodcasts() - .asFlow() - .mapToOneOrNull(dispatcher) - .map { it != null && it != 0L } + override fun countPodcasts(): Flow { + return database.podcastEntityQueries.countPodcasts().asFlow().mapToOne(dispatcher) } - override fun hasDownloads(): Flow { - return database.downloadableEpisodeEntityQueries.countDownloads() - .asFlow() - .mapToOneOrNull(dispatcher) - .map { it != null && it != 0L } + override fun countDownloads(): Flow { + return database.downloadableEpisodeEntityQueries.countDownloads().asFlow().mapToOne(dispatcher) } override fun isPodcastAvailableNonObservable(podcastId: Long): Boolean {