improve: retry to load source in some case it's late
This commit is contained in:
parent
19890ef4d4
commit
c92fdb5231
5 changed files with 101 additions and 36 deletions
|
|
@ -45,7 +45,7 @@ interface Tab : cafe.adriel.voyager.navigator.tab.Tab {
|
||||||
abstract class Screen : Screen {
|
abstract class Screen : Screen {
|
||||||
// known bug: https://github.com/mihonapp/mihon/issues/712
|
// known bug: https://github.com/mihonapp/mihon/issues/712
|
||||||
// This is where it create a key Screen#uuid:transition which causes exception Key ... was used multiple times
|
// This is where it create a key Screen#uuid:transition which causes exception Key ... was used multiple times
|
||||||
override val key: ScreenKey = "${this::class.simpleName}#$uniqueScreenKey"
|
override val key: ScreenKey = "$uniqueScreenKey#${this::class.simpleName}"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -127,12 +127,16 @@ data class BrowseSourceScreen(
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
if (screenModel.source is StubSource) {
|
// KMK -->
|
||||||
MissingSourceScreen(
|
screenModel.source.let {
|
||||||
source = screenModel.source,
|
// KMK <--
|
||||||
navigateUp = navigateUp,
|
if (it is StubSource) {
|
||||||
)
|
MissingSourceScreen(
|
||||||
return
|
source = it,
|
||||||
|
navigateUp = navigateUp,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import exh.source.mangaDexSourceIds
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
|
@ -118,7 +119,7 @@ open class BrowseSourceScreenModel(
|
||||||
|
|
||||||
var displayMode by sourcePreferences.sourceDisplayMode().asState(screenModelScope)
|
var displayMode by sourcePreferences.sourceDisplayMode().asState(screenModelScope)
|
||||||
|
|
||||||
val source = sourceManager.getOrStub(sourceId)
|
var source = sourceManager.getOrStub(sourceId)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val ehentaiBrowseDisplayMode by unsortedPreferences.enhancedEHentaiView().asState(screenModelScope)
|
val ehentaiBrowseDisplayMode by unsortedPreferences.enhancedEHentaiView().asState(screenModelScope)
|
||||||
|
|
@ -131,7 +132,18 @@ open class BrowseSourceScreenModel(
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (source is CatalogueSource) {
|
// KMK -->
|
||||||
|
screenModelScope.launchIO {
|
||||||
|
var retry = 10
|
||||||
|
while (source !is CatalogueSource && retry-- > 0) {
|
||||||
|
// Sometime source is late to load, so we need to wait a bit
|
||||||
|
delay(100)
|
||||||
|
source = sourceManager.getOrStub(sourceId)
|
||||||
|
}
|
||||||
|
val source = source
|
||||||
|
if (source !is CatalogueSource) return@launchIO
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
var query: String? = null
|
var query: String? = null
|
||||||
var listing = it.listing
|
var listing = it.listing
|
||||||
|
|
@ -147,38 +159,36 @@ open class BrowseSourceScreenModel(
|
||||||
toolbarQuery = query,
|
toolbarQuery = query,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!basePreferences.incognitoMode().get()) {
|
if (!basePreferences.incognitoMode().get()) {
|
||||||
sourcePreferences.lastUsedSource().set(source.id)
|
sourcePreferences.lastUsedSource().set(source.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val savedSearchFilters = savedSearch
|
val savedSearchFilters = savedSearch
|
||||||
val jsonFilters = filtersJson
|
val jsonFilters = filtersJson
|
||||||
val filters = state.value.filters
|
val filters = state.value.filters
|
||||||
if (savedSearchFilters != null) {
|
if (savedSearchFilters != null) {
|
||||||
val savedSearch = runBlocking { getExhSavedSearch.awaitOne(savedSearchFilters) { filters } }
|
val savedSearch = runBlocking { getExhSavedSearch.awaitOne(savedSearchFilters) { filters } }
|
||||||
if (savedSearch != null) {
|
if (savedSearch != null) {
|
||||||
search(query = savedSearch.query, filters = savedSearch.filterList)
|
search(query = savedSearch.query, filters = savedSearch.filterList)
|
||||||
|
}
|
||||||
|
} else if (jsonFilters != null) {
|
||||||
|
runCatching {
|
||||||
|
val filtersJson = Json.decodeFromString<JsonArray>(jsonFilters)
|
||||||
|
filterSerializer.deserialize(filters, filtersJson)
|
||||||
|
search(filters = filters)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (jsonFilters != null) {
|
|
||||||
runCatching {
|
|
||||||
val filtersJson = Json.decodeFromString<JsonArray>(jsonFilters)
|
|
||||||
filterSerializer.deserialize(filters, filtersJson)
|
|
||||||
search(filters = filters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source is CatalogueSource) {
|
|
||||||
getExhSavedSearch.subscribe(source.id, source::getFilterList)
|
getExhSavedSearch.subscribe(source.id, source::getFilterList)
|
||||||
.map { it.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, EXHSavedSearch::name)) }
|
.map { it.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, EXHSavedSearch::name)) }
|
||||||
.onEach { savedSearches ->
|
.onEach { savedSearches ->
|
||||||
mutableState.update { it.copy(savedSearches = savedSearches.toImmutableList()) }
|
mutableState.update { it.copy(savedSearches = savedSearches.toImmutableList()) }
|
||||||
}
|
}
|
||||||
.launchIn(screenModelScope)
|
.launchIn(screenModelScope)
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
// SY <--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -235,6 +245,9 @@ open class BrowseSourceScreenModel(
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
fun resetFilters() {
|
fun resetFilters() {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
|
|
||||||
mutableState.update { it.copy(filters = source.getFilterList()) }
|
mutableState.update { it.copy(filters = source.getFilterList()) }
|
||||||
|
|
@ -255,6 +268,10 @@ open class BrowseSourceScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String? = null, filters: FilterList? = null) {
|
fun search(query: String? = null, filters: FilterList? = null) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
// SY -->
|
// SY -->
|
||||||
if (filters != null && filters !== state.value.filters) {
|
if (filters != null && filters !== state.value.filters) {
|
||||||
|
|
@ -276,6 +293,10 @@ open class BrowseSourceScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun searchGenre(genreName: String) {
|
fun searchGenre(genreName: String) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
|
|
||||||
val defaultFilters = source.getFilterList()
|
val defaultFilters = source.getFilterList()
|
||||||
|
|
@ -493,6 +514,9 @@ open class BrowseSourceScreenModel(
|
||||||
onToast: (StringResource) -> Unit,
|
onToast: (StringResource) -> Unit,
|
||||||
) {
|
) {
|
||||||
screenModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return@launchIO
|
if (source !is CatalogueSource) return@launchIO
|
||||||
|
|
||||||
if (search.filterList == null && state.value.filters.isNotEmpty()) {
|
if (search.filterList == null && state.value.filters.isNotEmpty()) {
|
||||||
|
|
@ -529,6 +553,9 @@ open class BrowseSourceScreenModel(
|
||||||
fun saveSearch(
|
fun saveSearch(
|
||||||
name: String,
|
name: String,
|
||||||
) {
|
) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
screenModelScope.launchNonCancellable {
|
screenModelScope.launchNonCancellable {
|
||||||
val query = state.value.toolbarQuery?.takeUnless {
|
val query = state.value.toolbarQuery?.takeUnless {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,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.presentation.browse.MissingSourceScreen
|
||||||
import eu.kanade.presentation.browse.SourceFeedScreen
|
import eu.kanade.presentation.browse.SourceFeedScreen
|
||||||
import eu.kanade.presentation.browse.components.SourceFeedAddDialog
|
import eu.kanade.presentation.browse.components.SourceFeedAddDialog
|
||||||
import eu.kanade.presentation.browse.components.SourceFeedDeleteDialog
|
import eu.kanade.presentation.browse.components.SourceFeedDeleteDialog
|
||||||
|
|
@ -33,6 +34,7 @@ import exh.util.nullIfBlank
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||||
import tachiyomi.domain.source.model.SavedSearch
|
import tachiyomi.domain.source.model.SavedSearch
|
||||||
|
import tachiyomi.domain.source.model.StubSource
|
||||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||||
|
|
||||||
class SourceFeedScreen(val sourceId: Long) : Screen() {
|
class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
|
|
@ -50,6 +52,16 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
screenModel.source.let {
|
||||||
|
if (it is StubSource) {
|
||||||
|
MissingSourceScreen(
|
||||||
|
source = it,
|
||||||
|
navigateUp = navigator::pop,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
||||||
|
|
@ -169,7 +181,7 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
// navigator.replace(
|
// navigator.replace(
|
||||||
navigator.push(
|
navigator.push(
|
||||||
// KMK <--
|
// KMK <--
|
||||||
BrowseSourceScreen(
|
BrowseSourceScreen(
|
||||||
sourceId,
|
sourceId,
|
||||||
"id:$it",
|
"id:$it",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -73,7 +74,7 @@ open class SourceFeedScreenModel(
|
||||||
private val getExhSavedSearch: GetExhSavedSearch = Injekt.get(),
|
private val getExhSavedSearch: GetExhSavedSearch = Injekt.get(),
|
||||||
) : StateScreenModel<SourceFeedState>(SourceFeedState()) {
|
) : StateScreenModel<SourceFeedState>(SourceFeedState()) {
|
||||||
|
|
||||||
val source = sourceManager.getOrStub(sourceId)
|
var source = sourceManager.getOrStub(sourceId)
|
||||||
|
|
||||||
val sourceIsMangaDex = sourceId in mangaDexSourceIds
|
val sourceIsMangaDex = sourceId in mangaDexSourceIds
|
||||||
|
|
||||||
|
|
@ -82,14 +83,23 @@ open class SourceFeedScreenModel(
|
||||||
val startExpanded by uiPreferences.expandFilters().asState(screenModelScope)
|
val startExpanded by uiPreferences.expandFilters().asState(screenModelScope)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (source is CatalogueSource) {
|
// KMK -->
|
||||||
setFilters(source.getFilterList())
|
screenModelScope.launchIO {
|
||||||
|
var retry = 10
|
||||||
|
while (source !is CatalogueSource && retry-- > 0) {
|
||||||
|
// Sometime source is late to load, so we need to wait a bit
|
||||||
|
delay(100)
|
||||||
|
source = sourceManager.getOrStub(sourceId)
|
||||||
|
}
|
||||||
|
val source = source
|
||||||
|
if (source !is CatalogueSource) return@launchIO
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
|
setFilters(source.getFilterList())
|
||||||
screenModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
val searches = loadSearches()
|
val searches = loadSearches()
|
||||||
mutableState.update { it.copy(savedSearches = searches) }
|
mutableState.update { it.copy(savedSearches = searches) }
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeedSavedSearchBySourceId.subscribe(source.id)
|
getFeedSavedSearchBySourceId.subscribe(source.id)
|
||||||
.onEach {
|
.onEach {
|
||||||
val items = getSourcesToGetFeed(it)
|
val items = getSourcesToGetFeed(it)
|
||||||
|
|
@ -132,6 +142,9 @@ open class SourceFeedScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSourcesToGetFeed(feedSavedSearch: List<FeedSavedSearch>): ImmutableList<SourceFeedUI> {
|
private suspend fun getSourcesToGetFeed(feedSavedSearch: List<FeedSavedSearch>): ImmutableList<SourceFeedUI> {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return persistentListOf()
|
if (source !is CatalogueSource) return persistentListOf()
|
||||||
val savedSearches = getSavedSearchBySourceIdFeed.await(source.id)
|
val savedSearches = getSavedSearchBySourceIdFeed.await(source.id)
|
||||||
.associateBy { it.id }
|
.associateBy { it.id }
|
||||||
|
|
@ -154,6 +167,9 @@ open class SourceFeedScreenModel(
|
||||||
* Initiates get manga per feed.
|
* Initiates get manga per feed.
|
||||||
*/
|
*/
|
||||||
private fun getFeed(feedSavedSearch: List<SourceFeedUI>) {
|
private fun getFeed(feedSavedSearch: List<SourceFeedUI>) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
feedSavedSearch.map { sourceFeed ->
|
feedSavedSearch.map { sourceFeed ->
|
||||||
|
|
@ -222,6 +238,9 @@ open class SourceFeedScreenModel(
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
|
|
||||||
fun onFilter(onBrowseClick: (query: String?, filters: String?) -> Unit) {
|
fun onFilter(onBrowseClick: (query: String?, filters: String?) -> Unit) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
screenModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
val allDefault = state.value.filters == source.getFilterList()
|
val allDefault = state.value.filters == source.getFilterList()
|
||||||
|
|
@ -245,6 +264,9 @@ open class SourceFeedScreenModel(
|
||||||
onBrowseClick: (query: String?, searchId: Long) -> Unit,
|
onBrowseClick: (query: String?, searchId: Long) -> Unit,
|
||||||
onToast: (StringResource) -> Unit,
|
onToast: (StringResource) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
// KMK -->
|
||||||
|
val source = source
|
||||||
|
// KMK <--
|
||||||
if (source !is CatalogueSource) return
|
if (source !is CatalogueSource) return
|
||||||
screenModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
if (search.filterList == null && state.value.filters.isNotEmpty()) {
|
if (search.filterList == null && state.value.filters.isNotEmpty()) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue