Fix multiple issues regarding sources loading too late

This commit is contained in:
Jobobby04 2024-03-15 19:51:56 -04:00
parent 202900edf0
commit 31e5ba4caf
17 changed files with 126 additions and 31 deletions

View File

@ -18,6 +18,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
@ -336,19 +337,15 @@ class DownloadCache(
}
// Try to wait until extensions and sources have loaded
var sources = getSources()
if (sources.isEmpty()) {
withTimeoutOrNull(30.seconds) {
while (!extensionManager.isInitialized) {
delay(2.seconds)
}
// SY -->
var sources = emptyList<Source>()
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()
}
// SY <--
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }

View File

@ -26,6 +26,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.map
@ -53,8 +54,10 @@ class ExtensionManager(
private val trustExtension: TrustExtension = Injekt.get(),
) {
var isInitialized = false
private set
// SY -->
private val _isInitialized = MutableStateFlow(false)
val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
// SY <--
/**
* API where all the available extensions can be found.
@ -135,9 +138,9 @@ class ExtensionManager(
.map { it.extension }
// SY -->
.filterNotBlacklisted()
// SY <--
isInitialized = true
_isInitialized.value = true
// SY <--
}
// EXH -->

View File

@ -29,6 +29,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.combine
import kotlinx.coroutines.flow.map
@ -103,6 +105,7 @@ class AndroidSourceManager(
}
}
sourcesMapFlow.value = mutableMap
_isInitialized.value = true
}
}
@ -186,6 +189,9 @@ class AndroidSourceManager(
}
// SY -->
private val _isInitialized = MutableStateFlow(false)
override val isInitialized: StateFlow<Boolean> = _isInitialized.asStateFlow()
override fun getVisibleOnlineSources() = sourcesMapFlow.value.values
.filterIsInstance<HttpSource>()
.filter {

View File

@ -39,8 +39,10 @@ import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.sourcePreferences
import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito
import exh.source.EnhancedHttpSource
import exh.ui.ifSourcesLoaded
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -48,6 +50,11 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow
@ -130,7 +137,7 @@ class SourcePreferencesFragment : PreferenceFragmentCompat() {
// SY -->
val source = Injekt.get<SourceManager>()
.getOrStub(sourceId)
?.let { source ->
.let { source ->
if (source is EnhancedHttpSource) {
if (source.enhancedSource is ConfigurableSource) {
source.source()
@ -141,7 +148,6 @@ class SourcePreferencesFragment : PreferenceFragmentCompat() {
source
}
}
?: throw NullPointerException("source = null, SOURCE_ID = $SOURCE_ID")
// SY <--
val sourceScreen = preferenceManager.createPreferenceScreen(requireContext())

View File

@ -22,10 +22,12 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import eu.kanade.tachiyomi.ui.browse.source.browse.SourceFilterDialog
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import exh.ui.ifSourcesLoaded
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.core.common.Constants
import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.source.local.LocalSource
data class SourceSearchScreen(
@ -36,6 +38,11 @@ data class SourceSearchScreen(
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow

View File

@ -56,6 +56,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import eu.kanade.tachiyomi.util.system.toast
import exh.md.follows.MangaDexFollowsScreen
import exh.ui.ifSourcesLoaded
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
@ -66,6 +67,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.LocalSource
data class BrowseSourceScreen(
@ -84,6 +86,11 @@ data class BrowseSourceScreen(
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel {
BrowseSourceScreenModel(
sourceId = sourceId,

View File

@ -19,15 +19,22 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.SourceFilterDialog
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.util.system.toast
import exh.md.follows.MangaDexFollowsScreen
import exh.ui.ifSourcesLoaded
import exh.util.nullIfBlank
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.interactor.GetRemoteManga
import tachiyomi.domain.source.model.SavedSearch
import tachiyomi.presentation.core.screens.LoadingScreen
class SourceFeedScreen(val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { SourceFeedScreenModel(sourceId) }
val state by screenModel.state.collectAsState()
val navigator = LocalNavigator.currentOrThrow

View File

@ -14,6 +14,7 @@ import eu.kanade.presentation.browse.GlobalSearchScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import exh.ui.ifSourcesLoaded
import tachiyomi.presentation.core.screens.LoadingScreen
class GlobalSearchScreen(
@ -23,6 +24,11 @@ class GlobalSearchScreen(
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel {

View File

@ -64,6 +64,7 @@ import exh.recs.RecommendsScreen
import exh.source.MERGED_SOURCE_ID
import exh.source.getMainSource
import exh.source.isMdBasedSource
import exh.ui.ifSourcesLoaded
import exh.ui.metadata.MetadataViewScreen
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.launchIn
@ -98,6 +99,11 @@ class MangaScreen(
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val context = LocalContext.current
val haptic = LocalHapticFeedback.current

View File

@ -91,6 +91,7 @@ import eu.kanade.tachiyomi.util.system.toShareIntent
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent
import exh.source.isEhBasedSource
import exh.ui.ifSourcesLoaded
import exh.util.defaultReaderType
import exh.util.mangaType
import kotlinx.collections.immutable.persistentSetOf
@ -391,6 +392,10 @@ class ReaderActivity : BaseActivity() {
)
}
if (!ifSourcesLoaded()) {
return@setComposeContent
}
val isHttpSource = viewModel.getSource() is HttpSource
val isFullscreen by readerPreferences.fullscreen().collectAsState()
val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState()

View File

@ -63,6 +63,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
@ -336,6 +337,7 @@ class ReaderViewModel @JvmOverloads constructor(
val manga = getManga.await(mangaId)
if (manga != null) {
// SY -->
sourceManager.isInitialized.first { it }
val source = sourceManager.getOrStub(manga.source)
val metadataSource = source.getMainSource<MetadataSource<*, *>>()
val metadata = if (metadataSource != null) {

View File

@ -23,15 +23,22 @@ import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import eu.kanade.tachiyomi.ui.category.CategoryScreen
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import exh.ui.ifSourcesLoaded
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope()
val haptic = LocalHapticFeedback.current

View File

@ -15,15 +15,22 @@ import eu.kanade.presentation.browse.BrowseSourceContent
import eu.kanade.presentation.browse.components.BrowseSourceSimpleToolbar
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import exh.ui.ifSourcesLoaded
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { MangaDexSimilarScreenModel(mangaId, sourceId) }
val state by screenModel.state.collectAsState()
val navigator = LocalNavigator.currentOrThrow

View File

@ -16,13 +16,20 @@ import eu.kanade.presentation.browse.BrowseSourceContent
import eu.kanade.presentation.browse.components.BrowseSourceSimpleToolbar
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
import exh.ui.ifSourcesLoaded
import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.LoadingScreen
class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
@Composable
override fun Content() {
if (!ifSourcesLoaded()) {
LoadingScreen()
return
}
val screenModel = rememberScreenModel { RecommendsScreenModel(mangaId, sourceId) }
val state by screenModel.state.collectAsState()
val navigator = LocalNavigator.currentOrThrow

View File

@ -0,0 +1,13 @@
package exh.ui
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

@ -28,19 +28,22 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.view.setComposeContent
import exh.GalleryAddEvent
import exh.GalleryAdder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import tachiyomi.core.common.Constants
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.Scaffold
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class InterceptActivity : BaseActivity() {
private var statusJob: Job? = null
@ -108,7 +111,11 @@ class InterceptActivity : BaseActivity() {
private fun processLink() {
if (Intent.ACTION_VIEW == intent.action) {
loadGallery(intent.dataString!!)
lifecycleScope.launchIO {
// wait for sources to load
Injekt.get<SourceManager>().isInitialized.first { it }
loadGallery(intent.dataString!!)
}
}
}
@ -167,8 +174,7 @@ class InterceptActivity : BaseActivity() {
private val galleryAdder = GalleryAdder()
@Synchronized
fun loadGallery(gallery: String) {
suspend fun loadGallery(gallery: String) {
// Do not load gallery if already loading
if (status.value is InterceptResult.Idle) {
status.value = InterceptResult.Loading
@ -178,7 +184,10 @@ class InterceptActivity : BaseActivity() {
.setTitle(MR.strings.label_sources.getString(this))
.setSingleChoiceItems(sources.map { it.toString() }.toTypedArray(), 0) { dialog, index ->
dialog.dismiss()
loadGalleryEnd(gallery, sources[index])
lifecycleScope.launchIO {
loadGalleryEnd(gallery, sources[index])
}
}
.show()
} else {
@ -187,15 +196,12 @@ class InterceptActivity : BaseActivity() {
}
}
private fun loadGalleryEnd(gallery: String, source: UrlImportableSource? = null) {
// Load gallery async
lifecycleScope.launch(Dispatchers.IO) {
val result = galleryAdder.addGallery(this@InterceptActivity, gallery, forceSource = source)
private suspend fun loadGalleryEnd(gallery: String, source: UrlImportableSource? = null) {
val result = galleryAdder.addGallery(this@InterceptActivity, gallery, forceSource = source)
status.value = when (result) {
is GalleryAddEvent.Success -> InterceptResult.Success(result.manga.id, result.manga, result.chapter)
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
}
status.value = when (result) {
is GalleryAddEvent.Success -> InterceptResult.Success(result.manga.id, result.manga, result.chapter)
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
}
}

View File

@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import tachiyomi.domain.source.model.StubSource
interface SourceManager {
@ -19,6 +20,8 @@ interface SourceManager {
fun getCatalogueSources(): List<CatalogueSource>
// SY -->
val isInitialized: StateFlow<Boolean>
fun getVisibleOnlineSources(): List<HttpSource>
fun getVisibleCatalogueSources(): List<CatalogueSource>