Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle case when user has no subscriptions or no downloads more reliably #82

Merged
merged 2 commits into from
Aug 17, 2024
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 @@ -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
Expand All @@ -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
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ class SubscriptionsPresenterTest : BasePresenterTest<SubscriptionsUIEvent>() {
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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ interface PodcastsRepository {

fun isPodcastFromSubscriptionsNonObservable(podcastId: Long): Boolean

fun hasSubscriptions(): Flow<Boolean>
fun countSubscriptions(): Flow<Long>

fun hasDownloads(): Flow<Boolean>
fun countDownloads(): Flow<Long>

suspend fun getEpisode(episodeId: Long, podcastArtworkUrl: String, forceRefresh: Boolean): Episode?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ class DefaultPodcastsRepository @Inject constructor(
return podcastsDao.isPodcastAvailableNonObservable(podcastId)
}

override fun hasSubscriptions(): Flow<Boolean> = podcastsDao.hasPodcasts()
override fun countSubscriptions(): Flow<Long> = podcastsDao.countPodcasts()

override fun hasDownloads(): Flow<Boolean> = podcastsDao.hasDownloads()
override fun countDownloads(): Flow<Long> = podcastsDao.countDownloads()

override suspend fun getEpisode(episodeId: Long, podcastArtworkUrl: String, forceRefresh: Boolean): Episode? {
suspend fun fetchFromNetworkAndRefresh(): Episode? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -35,9 +36,9 @@ interface PodcastsDao {

fun isPodcastAvailable(podcastId: Long): Flow<Boolean>

fun hasPodcasts(): Flow<Boolean>
fun countPodcasts(): Flow<Long>

fun hasDownloads(): Flow<Boolean>
fun countDownloads(): Flow<Long>

fun isPodcastAvailableNonObservable(podcastId: Long): Boolean

Expand Down Expand Up @@ -145,18 +146,12 @@ class DefaultPodcastsDao @Inject constructor(
.map { it == 1L }
}

override fun hasPodcasts(): Flow<Boolean> {
return database.podcastEntityQueries.countPodcasts()
.asFlow()
.mapToOneOrNull(dispatcher)
.map { it != null && it != 0L }
override fun countPodcasts(): Flow<Long> {
return database.podcastEntityQueries.countPodcasts().asFlow().mapToOne(dispatcher)
}

override fun hasDownloads(): Flow<Boolean> {
return database.downloadableEpisodeEntityQueries.countDownloads()
.asFlow()
.mapToOneOrNull(dispatcher)
.map { it != null && it != 0L }
override fun countDownloads(): Flow<Long> {
return database.downloadableEpisodeEntityQueries.countDownloads().asFlow().mapToOne(dispatcher)
}

override fun isPodcastAvailableNonObservable(podcastId: Long): Boolean {
Expand Down
Loading