Fix multiple issues regarding sources loading too late

This commit is contained in:
Jobobby04 2024-03-15 19:51:56 -04:00 committed by AntsyLich
parent f087135876
commit a08e03f5cb
No known key found for this signature in database
12 changed files with 72 additions and 14 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.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@Composable
fun ifSourcesLoaded(): Boolean {
return remember { Injekt.get<SourceManager>().isInitialized }.collectAsState().value
}

View file

@ -18,6 +18,7 @@ import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
@ -311,19 +312,13 @@ class DownloadCache(
} }
// Try to wait until extensions and sources have loaded // Try to wait until extensions and sources have loaded
var sources = getSources() var sources = emptyList<Source>()
if (sources.isEmpty()) {
withTimeoutOrNull(30.seconds) { withTimeoutOrNull(30.seconds) {
while (!extensionManager.isInitialized) { extensionManager.isInitialized.first { it }
delay(2.seconds) 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 } 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.async
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import logcat.LogPriority import logcat.LogPriority
@ -41,8 +42,8 @@ class ExtensionManager(
private val trustExtension: TrustExtension = Injekt.get(), private val trustExtension: TrustExtension = Injekt.get(),
) { ) {
var isInitialized = false private val _isInitialized = MutableStateFlow(false)
private set val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
/** /**
* API where all the available extensions can be found. * API where all the available extensions can be found.
@ -108,7 +109,7 @@ class ExtensionManager(
.filterIsInstance<LoadResult.Untrusted>() .filterIsInstance<LoadResult.Untrusted>()
.map { it.extension } .map { it.extension }
isInitialized = true _isInitialized.value = true
} }
/** /**

View file

@ -9,6 +9,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -28,6 +30,9 @@ class AndroidSourceManager(
private val sourceRepository: StubSourceRepository, private val sourceRepository: StubSourceRepository,
) : SourceManager { ) : SourceManager {
private val _isInitialized = MutableStateFlow(false)
override val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
private val downloadManager: DownloadManager by injectLazy() private val downloadManager: DownloadManager by injectLazy()
private val scope = CoroutineScope(Job() + Dispatchers.IO) private val scope = CoroutineScope(Job() + Dispatchers.IO)
@ -60,6 +65,7 @@ class AndroidSourceManager(
} }
} }
sourcesMapFlow.value = mutableMap sourcesMapFlow.value = mutableMap
_isInitialized.value = true
} }
} }

View file

@ -31,6 +31,7 @@ import androidx.preference.forEach
import androidx.preference.getOnBindEditTextListener import androidx.preference.getOnBindEditTextListener
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifSourcesLoaded
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -40,6 +41,7 @@ import eu.kanade.tachiyomi.source.sourcePreferences
import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -47,6 +49,11 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen() {
@Composable @Composable
override fun Content() { override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val context = LocalContext.current val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow 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.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifSourcesLoaded
import eu.kanade.presentation.browse.BrowseSourceContent import eu.kanade.presentation.browse.BrowseSourceContent
import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.presentation.util.Screen 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.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.LocalSource import tachiyomi.source.local.LocalSource
data class SourceSearchScreen( data class SourceSearchScreen(
@ -44,6 +46,11 @@ data class SourceSearchScreen(
@Composable @Composable
override fun Content() { override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope() 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.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifSourcesLoaded
import eu.kanade.presentation.browse.BrowseSourceContent import eu.kanade.presentation.browse.BrowseSourceContent
import eu.kanade.presentation.browse.MissingSourceScreen import eu.kanade.presentation.browse.MissingSourceScreen
import eu.kanade.presentation.browse.components.BrowseSourceToolbar import eu.kanade.presentation.browse.components.BrowseSourceToolbar
@ -60,6 +61,7 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.LocalSource import tachiyomi.source.local.LocalSource
data class BrowseSourceScreen( data class BrowseSourceScreen(
@ -73,6 +75,11 @@ data class BrowseSourceScreen(
@Composable @Composable
override fun Content() { override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId, listingQuery) } val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId, listingQuery) }
val state by screenModel.state.collectAsState() 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.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.core.util.ifSourcesLoaded
import eu.kanade.presentation.browse.GlobalSearchScreen import eu.kanade.presentation.browse.GlobalSearchScreen
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
@ -23,6 +24,11 @@ class GlobalSearchScreen(
@Composable @Composable
override fun Content() { override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { val screenModel = rememberScreenModel {

View file

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

View file

@ -40,6 +40,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.elevation.SurfaceColors import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.transition.platform.MaterialContainerTransform import com.google.android.material.transition.platform.MaterialContainerTransform
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.core.util.ifSourcesLoaded
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.presentation.reader.DisplayRefreshHost import eu.kanade.presentation.reader.DisplayRefreshHost
import eu.kanade.presentation.reader.OrientationSelectDialog import eu.kanade.presentation.reader.OrientationSelectDialog
@ -344,6 +345,10 @@ class ReaderActivity : BaseActivity() {
) )
} }
if (!ifSourcesLoaded()) {
return@setComposeContent
}
val isHttpSource = viewModel.getSource() is HttpSource val isHttpSource = viewModel.getSource() is HttpSource
val isFullscreen by readerPreferences.fullscreen().collectAsState() val isFullscreen by readerPreferences.fullscreen().collectAsState()
val flashOnPageChange by readerPreferences.flashOnPageChange().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.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -264,6 +265,7 @@ class ReaderViewModel @JvmOverloads constructor(
try { try {
val manga = getManga.await(mangaId) val manga = getManga.await(mangaId)
if (manga != null) { if (manga != null) {
sourceManager.isInitialized.first { it }
mutableState.update { it.copy(manga = manga) } mutableState.update { it.copy(manga = manga) }
if (chapterId == -1L) chapterId = initialChapterId if (chapterId == -1L) chapterId = initialChapterId

View file

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