Fix multiple issues regarding sources loading too late

Co-authored-by: jobobby04 <17078382+jobobby04@users.noreply.github.com>
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
This commit is contained in:
Secozzi 2024-07-02 13:19:38 +02:00
parent 94730b153e
commit fd5d568a10
No known key found for this signature in database
GPG key ID: 71E9C97D8DDC2662
23 changed files with 141 additions and 29 deletions

View file

@ -0,0 +1,13 @@
package eu.kanade.core.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import tachiyomi.domain.source.anime.service.AnimeSourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@Composable
fun ifAnimeSourcesLoaded(): Boolean {
return remember { Injekt.get<AnimeSourceManager>().isInitialized }.collectAsState().value
}

View file

@ -0,0 +1,13 @@
package eu.kanade.core.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import tachiyomi.domain.source.manga.service.MangaSourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@Composable
fun ifMangaSourcesLoaded(): Boolean {
return remember { Injekt.get<MangaSourceManager>().isInitialized }.collectAsState().value
}

View file

@ -16,6 +16,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@ -318,18 +319,12 @@ class AnimeDownloadCache(
}
// Try to wait until extensions and sources have loaded
var sources = getSources()
if (sources.isEmpty()) {
withTimeoutOrNull(30.seconds) {
while (!extensionManager.isInitialized) {
delay(2.seconds)
}
var sources = emptyList<AnimeSource>()
withTimeoutOrNull(30.seconds) {
extensionManager.isInitialized.first { it }
sourceManager.isInitialized.first { it }
while (extensionManager.availableExtensionsFlow.value.isNotEmpty() && sources.isEmpty()) {
delay(2.seconds)
sources = getSources()
}
}
sources = getSources()
}
val sourceMap = sources.associate {

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@ -342,18 +343,12 @@ class MangaDownloadCache(
}
// Try to wait until extensions and sources have loaded
var sources = getSources()
if (sources.isEmpty()) {
withTimeoutOrNull(30.seconds) {
while (!extensionManager.isInitialized) {
delay(2.seconds)
}
var sources = emptyList<MangaSource>()
withTimeoutOrNull(30.seconds) {
extensionManager.isInitialized.first { it }
sourceManager.isInitialized.first { it }
while (extensionManager.availableExtensionsFlow.value.isNotEmpty() && sources.isEmpty()) {
delay(2.seconds)
sources = getSources()
}
}
sources = getSources()
}
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }

View file

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow
import logcat.LogPriority
@ -44,8 +45,8 @@ class AnimeExtensionManager(
private val trustExtension: TrustAnimeExtension = Injekt.get(),
) {
var isInitialized = false
private set
private val _isInitialized = MutableStateFlow(false)
val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
/**
* API where all the available anime extensions can be found.
@ -119,7 +120,7 @@ class AnimeExtensionManager(
.filterIsInstance<AnimeLoadResult.Untrusted>()
.map { it.extension }
isInitialized = true
_isInitialized.value = true
}
/**

View file

@ -16,10 +16,10 @@ import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow
import logcat.LogPriority
import tachiyomi.core.common.preference.plusAssign
import tachiyomi.core.common.util.lang.launchNow
import tachiyomi.core.common.util.lang.withUIContext
import tachiyomi.core.common.util.system.logcat
@ -42,8 +42,8 @@ class MangaExtensionManager(
private val trustExtension: TrustMangaExtension = Injekt.get(),
) {
var isInitialized = false
private set
private val _isInitialized = MutableStateFlow(false)
val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
/**
* API where all the available extensions can be found.
@ -109,7 +109,7 @@ class MangaExtensionManager(
.filterIsInstance<MangaLoadResult.Untrusted>()
.map { it.extension }
isInitialized = true
_isInitialized.value = true
}
/**

View file

@ -11,6 +11,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@ -29,6 +31,10 @@ class AndroidAnimeSourceManager(
private val extensionManager: AnimeExtensionManager,
private val sourceRepository: AnimeStubSourceRepository,
) : AnimeSourceManager {
private val _isInitialized = MutableStateFlow(false)
override val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
private val downloadManager: AnimeDownloadManager by injectLazy()
private val scope = CoroutineScope(Job() + Dispatchers.IO)
@ -61,6 +67,7 @@ class AndroidAnimeSourceManager(
}
}
sourcesMapFlow.value = mutableMap
_isInitialized.value = true
}
}

View file

@ -11,6 +11,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@ -29,6 +31,10 @@ class AndroidMangaSourceManager(
private val extensionManager: MangaExtensionManager,
private val sourceRepository: MangaStubSourceRepository,
) : MangaSourceManager {
private val _isInitialized = MutableStateFlow(false)
override val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
private val downloadManager: MangaDownloadManager by injectLazy()
private val scope = CoroutineScope(Job() + Dispatchers.IO)
@ -61,6 +67,7 @@ class AndroidMangaSourceManager(
}
}
sourcesMapFlow.value = mutableMap
_isInitialized.value = true
}
}

View file

@ -31,6 +31,7 @@ import androidx.preference.forEach
import androidx.preference.getOnBindEditTextListener
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifAnimeSourcesLoaded
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
@ -40,6 +41,7 @@ import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito
import tachiyomi.domain.source.anime.service.AnimeSourceManager
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -47,6 +49,11 @@ class AnimeSourcePreferencesScreen(val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifAnimeSourcesLoaded()) {
LoadingScreen()
return
}
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow

View file

@ -18,6 +18,7 @@ import androidx.paging.compose.collectAsLazyPagingItems
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifAnimeSourcesLoaded
import eu.kanade.presentation.browse.anime.BrowseAnimeSourceContent
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.presentation.util.Screen
@ -34,6 +35,7 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.entries.anime.LocalAnimeSource
data class AnimeSourceSearchScreen(
@ -44,6 +46,11 @@ data class AnimeSourceSearchScreen(
@Composable
override fun Content() {
if (!ifAnimeSourcesLoaded()) {
LoadingScreen()
return
}
val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope()

View file

@ -35,6 +35,7 @@ import androidx.paging.compose.collectAsLazyPagingItems
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifAnimeSourcesLoaded
import eu.kanade.presentation.browse.anime.BrowseAnimeSourceContent
import eu.kanade.presentation.browse.anime.MissingSourceScreen
import eu.kanade.presentation.browse.anime.components.BrowseAnimeSourceToolbar
@ -60,6 +61,7 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.entries.anime.LocalAnimeSource
data class BrowseAnimeSourceScreen(
@ -73,6 +75,11 @@ data class BrowseAnimeSourceScreen(
@Composable
override fun Content() {
if (!ifAnimeSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { BrowseAnimeSourceScreenModel(sourceId, listingQuery) }
val state by screenModel.state.collectAsState()

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.setValue
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifAnimeSourcesLoaded
import eu.kanade.presentation.browse.anime.GlobalAnimeSearchScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.anime.source.browse.BrowseAnimeSourceScreen
@ -23,6 +24,11 @@ class GlobalAnimeSearchScreen(
@Composable
override fun Content() {
if (!ifAnimeSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel {

View file

@ -31,6 +31,7 @@ import androidx.preference.forEach
import androidx.preference.getOnBindEditTextListener
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
@ -40,6 +41,7 @@ import eu.kanade.tachiyomi.source.sourcePreferences
import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito
import tachiyomi.domain.source.manga.service.MangaSourceManager
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -47,6 +49,11 @@ class MangaSourcePreferencesScreen(val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifMangaSourcesLoaded()) {
LoadingScreen()
return
}
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow

View file

@ -18,6 +18,7 @@ import androidx.paging.compose.collectAsLazyPagingItems
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.presentation.browse.manga.BrowseSourceContent
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.presentation.util.Screen
@ -34,6 +35,7 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.entries.manga.LocalMangaSource
data class MangaSourceSearchScreen(
@ -44,6 +46,11 @@ data class MangaSourceSearchScreen(
@Composable
override fun Content() {
if (!ifMangaSourcesLoaded()) {
LoadingScreen()
return
}
val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope()

View file

@ -35,6 +35,7 @@ import androidx.paging.compose.collectAsLazyPagingItems
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.presentation.browse.anime.components.RemoveEntryDialog
import eu.kanade.presentation.browse.manga.BrowseSourceContent
import eu.kanade.presentation.browse.manga.MissingSourceScreen
@ -60,6 +61,7 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.entries.manga.LocalMangaSource
data class BrowseMangaSourceScreen(
@ -73,6 +75,11 @@ data class BrowseMangaSourceScreen(
@Composable
override fun Content() {
if (!ifMangaSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { BrowseMangaSourceScreenModel(sourceId, listingQuery) }
val state by screenModel.state.collectAsState()

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.setValue
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.presentation.browse.manga.GlobalMangaSearchScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.manga.source.browse.BrowseMangaSourceScreen
@ -23,6 +24,11 @@ class GlobalMangaSearchScreen(
@Composable
override fun Content() {
if (!ifMangaSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel {

View file

@ -20,6 +20,7 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifAnimeSourcesLoaded
import eu.kanade.domain.entries.anime.model.hasCustomCover
import eu.kanade.domain.entries.anime.model.toSAnime
import eu.kanade.presentation.category.components.ChangeCategoryDialog
@ -76,6 +77,11 @@ class AnimeScreen(
@Composable
override fun Content() {
if (!ifAnimeSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val context = LocalContext.current
val haptic = LocalHapticFeedback.current

View file

@ -22,6 +22,7 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.domain.entries.manga.model.hasCustomCover
import eu.kanade.domain.entries.manga.model.toSManga
import eu.kanade.presentation.category.components.ChangeCategoryDialog
@ -74,6 +75,11 @@ class MangaScreen(
@Composable
override fun Content() {
if (!ifMangaSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val context = LocalContext.current
val haptic = LocalHapticFeedback.current

View file

@ -44,6 +44,7 @@ import `is`.xyz.mpv.Utils
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking
@ -245,6 +246,7 @@ class PlayerViewModel @JvmOverloads constructor(
return try {
val anime = getAnime.await(animeId)
if (anime != null) {
sourceManager.isInitialized.first { it }
if (episodeId == -1L) episodeId = initialEpisodeId
checkTrackers(anime)

View file

@ -40,6 +40,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.transition.platform.MaterialContainerTransform
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.core.util.ifMangaSourcesLoaded
import eu.kanade.domain.base.BasePreferences
import eu.kanade.presentation.reader.DisplayRefreshHost
import eu.kanade.presentation.reader.OrientationSelectDialog
@ -350,6 +351,10 @@ class ReaderActivity : BaseActivity() {
)
}
if (!ifMangaSourcesLoaded()) {
return@setComposeContent
}
val isHttpSource = viewModel.getSource() is HttpSource
val isFullscreen by readerPreferences.fullscreen().collectAsState()
val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState()

View file

@ -47,6 +47,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@ -270,6 +271,7 @@ class ReaderViewModel @JvmOverloads constructor(
try {
val manga = getManga.await(mangaId)
if (manga != null) {
sourceManager.isInitialized.first { it }
mutableState.update { it.copy(manga = manga) }
if (chapterId == -1L) chapterId = initialChapterId

View file

@ -4,10 +4,13 @@ import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
import eu.kanade.tachiyomi.animesource.AnimeSource
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import tachiyomi.domain.source.anime.model.StubAnimeSource
interface AnimeSourceManager {
val isInitialized: StateFlow<Boolean>
val catalogueSources: Flow<List<AnimeCatalogueSource>>
fun get(sourceKey: Long): AnimeSource?

View file

@ -4,10 +4,13 @@ import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.MangaSource
import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import tachiyomi.domain.source.manga.model.StubMangaSource
interface MangaSourceManager {
val isInitialized: StateFlow<Boolean>
val catalogueSources: Flow<List<CatalogueSource>>
fun get(sourceKey: Long): MangaSource?