Make DownloadQueueViewModel collect downloads only while subscribed (#3727)

Assisted-by: Claude:claude-opus-5
This commit is contained in:
AntsyLich
2026-08-08 20:04:29 +06:00
committed by GitHub
parent ae37c1651a
commit c68efd0e86
2 changed files with 18 additions and 25 deletions
@@ -19,7 +19,6 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.animateFloatingActionButton import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -41,6 +40,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
@@ -66,7 +66,7 @@ object DownloadQueueScreen : Screen() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val viewModel = viewModel<DownloadQueueViewModel>() val viewModel = viewModel<DownloadQueueViewModel>()
val downloadList by viewModel.state.collectAsState() val downloadList by viewModel.state.collectAsStateWithLifecycle()
val downloadCount by remember { val downloadCount by remember {
derivedStateOf { downloadList.sumOf { it.subItems.size } } derivedStateOf { downloadList.sumOf { it.subItems.size } }
} }
@@ -198,7 +198,7 @@ object DownloadQueueScreen : Screen() {
) )
}, },
floatingActionButton = { floatingActionButton = {
val isRunning by viewModel.isDownloaderRunning.collectAsState() val isRunning by viewModel.isDownloaderRunning.collectAsStateWithLifecycle()
SmallExtendedFloatingActionButton( SmallExtendedFloatingActionButton(
text = { text = {
val id = if (isRunning) { val id = if (isRunning) {
@@ -10,27 +10,36 @@ import eu.kanade.tachiyomi.databinding.DownloadListBinding
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
class DownloadQueueViewModel( class DownloadQueueViewModel(
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
) : ViewModel() { ) : ViewModel() {
private val _state = MutableStateFlow(emptyList<DownloadHeaderItem>()) val state: StateFlow<List<DownloadHeaderItem>> = downloadManager.queueState
val state = _state.asStateFlow() .map { downloads ->
downloads
.groupBy { it.source }
.map { entry ->
DownloadHeaderItem(entry.key.id, entry.key.name, entry.value.size).apply {
addSubItems(0, entry.value.map { DownloadItem(it, this) })
}
}
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), emptyList())
lateinit var controllerBinding: DownloadListBinding lateinit var controllerBinding: DownloadListBinding
@@ -116,22 +125,6 @@ class DownloadQueueViewModel(
} }
} }
init {
viewModelScope.launch {
downloadManager.queueState
.map { downloads ->
downloads
.groupBy { it.source }
.map { entry ->
DownloadHeaderItem(entry.key.id, entry.key.name, entry.value.size).apply {
addSubItems(0, entry.value.map { DownloadItem(it, this) })
}
}
}
.collect { newList -> _state.update { newList } }
}
}
override fun onCleared() { override fun onCleared() {
for (job in progressJobs.values) { for (job in progressJobs.values) {
job.cancel() job.cancel()
@@ -141,7 +134,7 @@ class DownloadQueueViewModel(
} }
val isDownloaderRunning = downloadManager.isDownloaderRunning val isDownloaderRunning = downloadManager.isDownloaderRunning
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), false)
fun getDownloadStatusFlow() = downloadManager.statusFlow() fun getDownloadStatusFlow() = downloadManager.statusFlow()
fun getDownloadProgressFlow() = downloadManager.progressFlow() fun getDownloadProgressFlow() = downloadManager.progressFlow()