Merge Latest and Browse into one screen (#7921)
* Merge Latest and Browse into one * Add back Latest button * Change context to IO instead of launching a job * Use loading screen when loading initial page (cherry picked from commit cc6aef693e1a15f695ffa7eebd968004a6557010) # Conflicts: # app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt # app/src/main/java/eu/kanade/presentation/browse/BrowseLatestScreen.kt # app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt # app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt # app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt # app/src/main/java/eu/kanade/presentation/browse/components/BrowseLatestToolbar.kt # app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt # app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowsePagingSource.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesPresenter.kt
This commit is contained in:
parent
3ba39f6557
commit
99d5d8b91f
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
package eu.kanade.data.source
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -6,20 +6,16 @@ import eu.kanade.tachiyomi.source.model.MangasPage
|
|||||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||||
|
|
||||||
class EHentaiBrowsePagingSource(val source: CatalogueSource, val query: String, val filters: FilterList) : BrowsePagingSource() {
|
abstract class EHentaiPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
|
||||||
|
|
||||||
private var lastMangaLink: String? = null
|
private var lastMangaLink: String? = null
|
||||||
|
|
||||||
|
abstract suspend fun fetchNextPage(currentPage: Int): MangasPage
|
||||||
|
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
val lastMangaLink = lastMangaLink
|
val lastMangaLink = lastMangaLink
|
||||||
|
|
||||||
val observable = if (query.isBlank() && filters.isEmpty()) {
|
val mangasPage = fetchNextPage(currentPage)
|
||||||
source.fetchPopularManga(currentPage)
|
|
||||||
} else {
|
|
||||||
source.fetchSearchManga(currentPage, query, filters)
|
|
||||||
}
|
|
||||||
|
|
||||||
val mangasPage = observable.awaitSingle()
|
|
||||||
|
|
||||||
mangasPage.mangas.lastOrNull()?.let {
|
mangasPage.mangas.lastOrNull()?.let {
|
||||||
this.lastMangaLink = it.url
|
this.lastMangaLink = it.url
|
||||||
@ -47,3 +43,21 @@ class EHentaiBrowsePagingSource(val source: CatalogueSource, val query: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EHentaiSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun fetchNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchSearchManga(currentPage, query, filters).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EHentaiPopularPagingSource(source: CatalogueSource) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun fetchNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchPopularManga(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EHentaiLatestPagingSource(source: CatalogueSource) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun fetchNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchLatestUpdates(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package eu.kanade.data.source
|
||||||
|
|
||||||
|
class NoResultsException : Exception()
|
@ -1,14 +1,19 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
package eu.kanade.data.source
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import androidx.paging.PagingState
|
import androidx.paging.PagingState
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
|
||||||
abstract class BrowsePagingSource : PagingSource<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?> /*SY <-- */>() {
|
abstract class SourcePagingSource(
|
||||||
|
protected val source: CatalogueSource,
|
||||||
|
) : SourcePagingSourceType() {
|
||||||
|
|
||||||
abstract suspend fun requestNextPage(currentPage: Int): MangasPage
|
abstract suspend fun requestNextPage(currentPage: Int): MangasPage
|
||||||
|
|
||||||
@ -18,6 +23,8 @@ abstract class BrowsePagingSource : PagingSource<Long, /*SY --> */ Pair<SManga,
|
|||||||
val mangasPage = try {
|
val mangasPage = try {
|
||||||
withIOContext {
|
withIOContext {
|
||||||
requestNextPage(page.toInt())
|
requestNextPage(page.toInt())
|
||||||
|
.takeIf { it.mangas.isNotEmpty() }
|
||||||
|
?: throw NoResultsException()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return LoadResult.Error(e)
|
return LoadResult.Error(e)
|
||||||
@ -38,10 +45,28 @@ abstract class BrowsePagingSource : PagingSource<Long, /*SY --> */ Pair<SManga,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRefreshKey(state: PagingState<Long, Pair<SManga, RaisedSearchMetadata?>>): Long? {
|
override fun getRefreshKey(state: PagingState<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */>): Long? {
|
||||||
return state.anchorPosition?.let { anchorPosition ->
|
return state.anchorPosition?.let { anchorPosition ->
|
||||||
val anchorPage = state.closestPageToPosition(anchorPosition)
|
val anchorPage = state.closestPageToPosition(anchorPosition)
|
||||||
anchorPage?.prevKey ?: anchorPage?.nextKey
|
anchorPage?.prevKey ?: anchorPage?.nextKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchSearchManga(currentPage, query, filters).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchPopularManga(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchLatestUpdates(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,15 @@ package eu.kanade.data.source
|
|||||||
|
|
||||||
import eu.kanade.data.DatabaseHandler
|
import eu.kanade.data.DatabaseHandler
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.domain.source.model.SourceWithCount
|
import eu.kanade.domain.source.model.SourceWithCount
|
||||||
import eu.kanade.domain.source.repository.SourceRepository
|
import eu.kanade.domain.source.repository.SourceRepository
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
|
import exh.source.isEhBasedSource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
@ -50,4 +54,38 @@ class SourceRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun search(
|
||||||
|
sourceId: Long,
|
||||||
|
query: String,
|
||||||
|
filterList: FilterList,
|
||||||
|
): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source.isEhBasedSource()) {
|
||||||
|
return EHentaiSearchPagingSource(source, query, filterList)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourceSearchPagingSource(source, query, filterList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPopular(sourceId: Long): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source.isEhBasedSource()) {
|
||||||
|
return EHentaiPopularPagingSource(source)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourcePopularPagingSource(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLatest(sourceId: Long): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source.isEhBasedSource()) {
|
||||||
|
return EHentaiLatestPagingSource(source)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourceLatestPagingSource(source)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ import eu.kanade.domain.manga.interactor.UpdateManga
|
|||||||
import eu.kanade.domain.manga.repository.MangaRepository
|
import eu.kanade.domain.manga.repository.MangaRepository
|
||||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
import eu.kanade.domain.source.interactor.GetEnabledSources
|
||||||
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
|
import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
@ -133,6 +134,7 @@ class DomainModule : InjektModule {
|
|||||||
addSingletonFactory<SourceDataRepository> { SourceDataRepositoryImpl(get()) }
|
addSingletonFactory<SourceDataRepository> { SourceDataRepositoryImpl(get()) }
|
||||||
addFactory { GetEnabledSources(get(), get()) }
|
addFactory { GetEnabledSources(get(), get()) }
|
||||||
addFactory { GetLanguagesWithSources(get(), get()) }
|
addFactory { GetLanguagesWithSources(get(), get()) }
|
||||||
|
addFactory { GetRemoteManga(get()) }
|
||||||
addFactory { GetSourcesWithFavoriteCount(get(), get()) }
|
addFactory { GetSourcesWithFavoriteCount(get(), get()) }
|
||||||
addFactory { GetSourcesWithNonLibraryManga(get()) }
|
addFactory { GetSourcesWithNonLibraryManga(get()) }
|
||||||
addFactory { SetMigrateSorting(get()) }
|
addFactory { SetMigrateSorting(get()) }
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
|
import eu.kanade.domain.source.repository.SourceRepository
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
|
||||||
|
class GetRemoteManga(
|
||||||
|
private val repository: SourceRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun subscribe(sourceId: Long, query: String, filterList: FilterList): SourcePagingSourceType {
|
||||||
|
return when (query) {
|
||||||
|
QUERY_POPULAR -> repository.getPopular(sourceId)
|
||||||
|
QUERY_LATEST -> repository.getLatest(sourceId)
|
||||||
|
else -> repository.search(sourceId, query, filterList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val QUERY_POPULAR = "eu.kanade.domain.source.interactor.POPULAR"
|
||||||
|
const val QUERY_LATEST = "eu.kanade.domain.source.interactor.LATEST"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package eu.kanade.domain.source.model
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
|
||||||
|
typealias SourcePagingSourceType = PagingSource<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */>
|
@ -1,7 +1,9 @@
|
|||||||
package eu.kanade.domain.source.repository
|
package eu.kanade.domain.source.repository
|
||||||
|
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.domain.source.model.SourceWithCount
|
import eu.kanade.domain.source.model.SourceWithCount
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface SourceRepository {
|
interface SourceRepository {
|
||||||
@ -13,4 +15,10 @@ interface SourceRepository {
|
|||||||
fun getSourcesWithFavoriteCount(): Flow<List<Pair<Source, Long>>>
|
fun getSourcesWithFavoriteCount(): Flow<List<Pair<Source, Long>>>
|
||||||
|
|
||||||
fun getSourcesWithNonLibraryManga(): Flow<List<SourceWithCount>>
|
fun getSourcesWithNonLibraryManga(): Flow<List<SourceWithCount>>
|
||||||
|
|
||||||
|
fun search(sourceId: Long, query: String, filterList: FilterList): SourcePagingSourceType
|
||||||
|
|
||||||
|
fun getPopular(sourceId: Long): SourcePagingSourceType
|
||||||
|
|
||||||
|
fun getLatest(sourceId: Long): SourcePagingSourceType
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
package eu.kanade.presentation.browse
|
|
||||||
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import eu.kanade.domain.manga.model.Manga
|
|
||||||
import eu.kanade.presentation.browse.components.BrowseLatestToolbar
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
|
||||||
import exh.source.isEhBasedSource
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BrowseLatestScreen(
|
|
||||||
presenter: BrowseSourcePresenter,
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
onMangaClick: (Manga) -> Unit,
|
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
|
||||||
onWebViewClick: () -> Unit,
|
|
||||||
// SY -->
|
|
||||||
onSettingsClick: () -> Unit,
|
|
||||||
// SY <--
|
|
||||||
) {
|
|
||||||
val columns by presenter.getColumnsPreferenceForCurrentOrientation()
|
|
||||||
|
|
||||||
val uriHandler = LocalUriHandler.current
|
|
||||||
|
|
||||||
val onHelpClick = {
|
|
||||||
uriHandler.openUri(LocalSource.HELP_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
topBar = { scrollBehavior ->
|
|
||||||
BrowseLatestToolbar(
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
source = presenter.source!!,
|
|
||||||
displayMode = presenter.displayMode.takeUnless { presenter.source!!.isEhBasedSource() && presenter.ehentaiBrowseDisplayMode },
|
|
||||||
onDisplayModeChange = { presenter.displayMode = it },
|
|
||||||
onHelpClick = onHelpClick,
|
|
||||||
onWebViewClick = onWebViewClick,
|
|
||||||
// SY -->
|
|
||||||
onSettingsClick = onSettingsClick,
|
|
||||||
// SY <--
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { paddingValues ->
|
|
||||||
BrowseSourceContent(
|
|
||||||
source = presenter.source,
|
|
||||||
mangaList = presenter.getMangaList().collectAsLazyPagingItems(),
|
|
||||||
getMangaState = { presenter.getManga(it) },
|
|
||||||
// SY -->
|
|
||||||
getMetadataState = { manga, metadata ->
|
|
||||||
presenter.getRaisedSearchMetadata(manga, metadata)
|
|
||||||
},
|
|
||||||
// SY <--
|
|
||||||
columns = columns,
|
|
||||||
// SY -->
|
|
||||||
ehentaiBrowseDisplayMode = presenter.ehentaiBrowseDisplayMode,
|
|
||||||
// SY <--
|
|
||||||
displayMode = presenter.displayMode,
|
|
||||||
snackbarHostState = remember { SnackbarHostState() },
|
|
||||||
contentPadding = paddingValues,
|
|
||||||
onWebViewClick = onWebViewClick,
|
|
||||||
onHelpClick = { uriHandler.openUri(MoreController.URL_HELP) },
|
|
||||||
onLocalSourceHelpClick = onHelpClick,
|
|
||||||
onMangaClick = onMangaClick,
|
|
||||||
onMangaLongClick = onMangaLongClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -43,7 +43,7 @@ fun BrowseMangadexFollowsScreen(
|
|||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = presenter.source,
|
state = presenter,
|
||||||
mangaList = mangaList,
|
mangaList = mangaList,
|
||||||
getMangaState = { presenter.getManga(it) },
|
getMangaState = { presenter.getManga(it) },
|
||||||
// SY -->
|
// SY -->
|
||||||
|
@ -31,7 +31,7 @@ fun BrowseRecommendationsScreen(
|
|||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = presenter.source,
|
state = presenter,
|
||||||
mangaList = presenter.getMangaList().collectAsLazyPagingItems(),
|
mangaList = presenter.getMangaList().collectAsLazyPagingItems(),
|
||||||
getMangaState = { presenter.getManga(it) },
|
getMangaState = { presenter.getManga(it) },
|
||||||
// SY -->
|
// SY -->
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Favorite
|
||||||
import androidx.compose.material.icons.outlined.FilterList
|
import androidx.compose.material.icons.outlined.FilterList
|
||||||
|
import androidx.compose.material.icons.outlined.NewReleases
|
||||||
|
import androidx.compose.material3.FilterChip
|
||||||
|
import androidx.compose.material3.FilterChipDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.SnackbarDuration
|
import androidx.compose.material3.SnackbarDuration
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
@ -20,10 +29,13 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.paging.LoadState
|
import androidx.paging.LoadState
|
||||||
import androidx.paging.compose.LazyPagingItems
|
import androidx.paging.compose.LazyPagingItems
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import eu.kanade.data.source.NoResultsException
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
|
import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
|
||||||
import eu.kanade.presentation.browse.components.BrowseSourceCompactGrid
|
import eu.kanade.presentation.browse.components.BrowseSourceCompactGrid
|
||||||
import eu.kanade.presentation.browse.components.BrowseSourceEHentaiList
|
import eu.kanade.presentation.browse.components.BrowseSourceEHentaiList
|
||||||
@ -31,12 +43,11 @@ import eu.kanade.presentation.browse.components.BrowseSourceList
|
|||||||
import eu.kanade.presentation.browse.components.BrowseSourceToolbar
|
import eu.kanade.presentation.browse.components.BrowseSourceToolbar
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
||||||
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.NoResultsException
|
|
||||||
import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode
|
import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
import eu.kanade.tachiyomi.widget.EmptyView
|
import eu.kanade.tachiyomi.widget.EmptyView
|
||||||
@ -47,7 +58,6 @@ import exh.source.isEhBasedSource
|
|||||||
fun BrowseSourceScreen(
|
fun BrowseSourceScreen(
|
||||||
presenter: BrowseSourcePresenter,
|
presenter: BrowseSourcePresenter,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
|
|
||||||
onFabClick: () -> Unit,
|
onFabClick: () -> Unit,
|
||||||
onMangaClick: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
onMangaLongClick: (Manga) -> Unit,
|
||||||
@ -74,7 +84,7 @@ fun BrowseSourceScreen(
|
|||||||
state = presenter,
|
state = presenter,
|
||||||
source = presenter.source!!,
|
source = presenter.source!!,
|
||||||
displayMode = presenter.displayMode.takeUnless { presenter.source!!.isEhBasedSource() && presenter.ehentaiBrowseDisplayMode },
|
displayMode = presenter.displayMode.takeUnless { presenter.source!!.isEhBasedSource() && presenter.ehentaiBrowseDisplayMode },
|
||||||
onDisplayModeChange = onDisplayModeChange,
|
onDisplayModeChange = { presenter.displayMode = it },
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
onWebViewClick = onWebViewClick,
|
onWebViewClick = onWebViewClick,
|
||||||
onHelpClick = onHelpClick,
|
onHelpClick = onHelpClick,
|
||||||
@ -86,31 +96,17 @@ fun BrowseSourceScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
// SY -->
|
BrowseSourceFloatingActionButton(
|
||||||
// if (presenter.filters.isNotEmpty()) {
|
isVisible = presenter.filters.isNotEmpty(),
|
||||||
ExtendedFloatingActionButton(
|
onFabClick = onFabClick,
|
||||||
modifier = Modifier.navigationBarsPadding(),
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
text = if (presenter.filters.isNotEmpty()) {
|
|
||||||
stringResource(id = R.string.action_filter)
|
|
||||||
} else {
|
|
||||||
stringResource(R.string.saved_searches)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
icon = { Icon(Icons.Outlined.FilterList, contentDescription = "") },
|
|
||||||
onClick = onFabClick,
|
|
||||||
)
|
)
|
||||||
// }
|
|
||||||
// SY <--
|
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = {
|
||||||
SnackbarHost(hostState = snackbarHostState)
|
SnackbarHost(hostState = snackbarHostState)
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = presenter.source,
|
state = presenter,
|
||||||
mangaList = mangaList,
|
mangaList = mangaList,
|
||||||
getMangaState = { presenter.getManga(it) },
|
getMangaState = { presenter.getManga(it) },
|
||||||
// SY -->
|
// SY -->
|
||||||
@ -130,18 +126,113 @@ fun BrowseSourceScreen(
|
|||||||
onLocalSourceHelpClick = onHelpClick,
|
onLocalSourceHelpClick = onHelpClick,
|
||||||
onMangaClick = onMangaClick,
|
onMangaClick = onMangaClick,
|
||||||
onMangaLongClick = onMangaLongClick,
|
onMangaLongClick = onMangaLongClick,
|
||||||
|
header = {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.horizontalScroll(rememberScrollState()),
|
||||||
|
) {
|
||||||
|
FilterChip(
|
||||||
|
selected = presenter.currentQuery == GetRemoteManga.QUERY_POPULAR,
|
||||||
|
onClick = {
|
||||||
|
presenter.resetFilter()
|
||||||
|
presenter.search(GetRemoteManga.QUERY_POPULAR)
|
||||||
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Favorite,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(FilterChipDefaults.IconSize),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = stringResource(id = R.string.popular))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (presenter.source?.supportsLatest == true) {
|
||||||
|
FilterChip(
|
||||||
|
selected = presenter.currentQuery == GetRemoteManga.QUERY_LATEST,
|
||||||
|
onClick = {
|
||||||
|
presenter.resetFilter()
|
||||||
|
presenter.search(GetRemoteManga.QUERY_LATEST)
|
||||||
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.NewReleases,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(FilterChipDefaults.IconSize),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = stringResource(id = R.string.latest))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/* SY --> if (presenter.filters.isNotEmpty())*/ run /* SY <-- */ {
|
||||||
|
FilterChip(
|
||||||
|
selected = presenter.currentQuery != GetRemoteManga.QUERY_POPULAR && presenter.currentQuery != GetRemoteManga.QUERY_LATEST,
|
||||||
|
onClick = onFabClick,
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.FilterList,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(FilterChipDefaults.IconSize),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
// SY -->
|
||||||
|
Text(
|
||||||
|
text = if (presenter.filters.isNotEmpty()) {
|
||||||
|
stringResource(id = R.string.action_filter)
|
||||||
|
} else {
|
||||||
|
stringResource(id = R.string.saved_searches)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// SY <--
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BrowseSourceFloatingActionButton(
|
||||||
|
modifier: Modifier = Modifier.navigationBarsPadding(),
|
||||||
|
isVisible: Boolean,
|
||||||
|
onFabClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
run {
|
||||||
|
ExtendedFloatingActionButton(
|
||||||
|
modifier = modifier,
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = if (isVisible) {
|
||||||
|
stringResource(id = R.string.action_filter)
|
||||||
|
} else {
|
||||||
|
stringResource(id = R.string.saved_searches)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
icon = { Icon(Icons.Outlined.FilterList, contentDescription = "") },
|
||||||
|
onClick = onFabClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BrowseSourceContent(
|
fun BrowseSourceContent(
|
||||||
source: CatalogueSource?,
|
state: BrowseSourceState,
|
||||||
mangaList: LazyPagingItems</* SY --> */Pair<Manga, RaisedSearchMetadata?>/* SY <-- */>,
|
mangaList: LazyPagingItems</* SY --> */Pair<Manga, RaisedSearchMetadata?>/* SY <-- */>,
|
||||||
getMangaState: @Composable ((Manga) -> State<Manga>),
|
getMangaState: @Composable ((Manga) -> State<Manga>),
|
||||||
// SY -->
|
// SY -->
|
||||||
getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State<RaisedSearchMetadata?>),
|
getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State<RaisedSearchMetadata?>),
|
||||||
// SY <--
|
// SY <--
|
||||||
|
header: (@Composable () -> Unit)? = null,
|
||||||
columns: GridCells,
|
columns: GridCells,
|
||||||
ehentaiBrowseDisplayMode: Boolean,
|
ehentaiBrowseDisplayMode: Boolean,
|
||||||
displayMode: LibraryDisplayMode,
|
displayMode: LibraryDisplayMode,
|
||||||
@ -186,7 +277,7 @@ fun BrowseSourceContent(
|
|||||||
if (mangaList.itemCount <= 0 && errorState != null && errorState is LoadState.Error) {
|
if (mangaList.itemCount <= 0 && errorState != null && errorState is LoadState.Error) {
|
||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
message = getErrorMessage(errorState),
|
message = getErrorMessage(errorState),
|
||||||
actions = if (source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) {
|
actions = if (state.source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) {
|
||||||
listOf(
|
listOf(
|
||||||
EmptyView.Action(R.string.local_source_help_guide, R.drawable.ic_help_24dp) { onLocalSourceHelpClick() },
|
EmptyView.Action(R.string.local_source_help_guide, R.drawable.ic_help_24dp) { onLocalSourceHelpClick() },
|
||||||
)
|
)
|
||||||
@ -204,8 +295,13 @@ fun BrowseSourceContent(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mangaList.itemCount == 0 && mangaList.loadState.refresh is LoadState.Loading) {
|
||||||
|
LoadingScreen()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
|
if (state.source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
|
||||||
BrowseSourceEHentaiList(
|
BrowseSourceEHentaiList(
|
||||||
mangaList = mangaList,
|
mangaList = mangaList,
|
||||||
getMangaState = getMangaState,
|
getMangaState = getMangaState,
|
||||||
@ -213,6 +309,7 @@ fun BrowseSourceContent(
|
|||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
onMangaClick = onMangaClick,
|
onMangaClick = onMangaClick,
|
||||||
onMangaLongClick = onMangaLongClick,
|
onMangaLongClick = onMangaLongClick,
|
||||||
|
header = header,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -230,6 +327,7 @@ fun BrowseSourceContent(
|
|||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
onMangaClick = onMangaClick,
|
onMangaClick = onMangaClick,
|
||||||
onMangaLongClick = onMangaLongClick,
|
onMangaLongClick = onMangaLongClick,
|
||||||
|
header = header,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
LibraryDisplayMode.List -> {
|
LibraryDisplayMode.List -> {
|
||||||
@ -242,6 +340,7 @@ fun BrowseSourceContent(
|
|||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
onMangaClick = onMangaClick,
|
onMangaClick = onMangaClick,
|
||||||
onMangaLongClick = onMangaLongClick,
|
onMangaLongClick = onMangaLongClick,
|
||||||
|
header = header,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@ -255,6 +354,7 @@ fun BrowseSourceContent(
|
|||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
onMangaClick = onMangaClick,
|
onMangaClick = onMangaClick,
|
||||||
onMangaLongClick = onMangaLongClick,
|
onMangaLongClick = onMangaLongClick,
|
||||||
|
header = header,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
@ -16,22 +17,31 @@ interface BrowseSourceState {
|
|||||||
val source: CatalogueSource?
|
val source: CatalogueSource?
|
||||||
var searchQuery: String?
|
var searchQuery: String?
|
||||||
val currentQuery: String
|
val currentQuery: String
|
||||||
|
val isUserQuery: Boolean
|
||||||
val filters: FilterList
|
val filters: FilterList
|
||||||
val filterItems: List<IFlexible<*>>
|
val filterItems: List<IFlexible<*>>
|
||||||
val appliedFilters: FilterList
|
val currentFilters: FilterList
|
||||||
var dialog: BrowseSourcePresenter.Dialog?
|
var dialog: BrowseSourcePresenter.Dialog?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BrowseSourceState(initialQuery: String?): BrowseSourceState {
|
fun BrowseSourceState(initialQuery: String?): BrowseSourceState {
|
||||||
return BrowseSourceStateImpl(initialQuery)
|
if (initialQuery == GetRemoteManga.QUERY_POPULAR || initialQuery == GetRemoteManga.QUERY_LATEST) {
|
||||||
|
return BrowseSourceStateImpl(initialCurrentQuery = initialQuery)
|
||||||
|
}
|
||||||
|
return BrowseSourceStateImpl(initialQuery = initialQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrowseSourceStateImpl(initialQuery: String?) : BrowseSourceState {
|
class BrowseSourceStateImpl(initialQuery: String? = null, initialCurrentQuery: String? = initialQuery) : BrowseSourceState {
|
||||||
override var source: CatalogueSource? by mutableStateOf(null)
|
override var source: CatalogueSource? by mutableStateOf(null)
|
||||||
override var searchQuery: String? by mutableStateOf(initialQuery)
|
override var searchQuery: String? by mutableStateOf(initialQuery)
|
||||||
override var currentQuery: String by mutableStateOf(initialQuery ?: "")
|
override var currentQuery: String by mutableStateOf(initialCurrentQuery ?: "")
|
||||||
|
override val isUserQuery: Boolean by derivedStateOf {
|
||||||
|
currentQuery.isNotEmpty() &&
|
||||||
|
currentQuery != GetRemoteManga.QUERY_POPULAR &&
|
||||||
|
currentQuery != GetRemoteManga.QUERY_LATEST
|
||||||
|
}
|
||||||
override var filters: FilterList by mutableStateOf(FilterList())
|
override var filters: FilterList by mutableStateOf(FilterList())
|
||||||
override val filterItems: List<IFlexible<*>> by derivedStateOf { filters.toItems() }
|
override val filterItems: List<IFlexible<*>> by derivedStateOf { filters.toItems() }
|
||||||
override var appliedFilters by mutableStateOf(FilterList())
|
override var currentFilters by mutableStateOf(FilterList())
|
||||||
override var dialog: BrowseSourcePresenter.Dialog? by mutableStateOf(null)
|
override var dialog: BrowseSourcePresenter.Dialog? by mutableStateOf(null)
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,81 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.glance.LocalContext
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.presentation.browse.components.BrowseSourceSearchToolbar
|
||||||
|
import eu.kanade.presentation.components.Scaffold
|
||||||
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceSearchScreen(
|
fun SourceSearchScreen(
|
||||||
presenter: BrowseSourcePresenter,
|
presenter: BrowseSourcePresenter,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
onFabClick: () -> Unit,
|
onFabClick: () -> Unit,
|
||||||
onClickManga: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
// SY -->
|
onWebViewClick: () -> Unit,
|
||||||
onSettingsClick: () -> Unit,
|
|
||||||
// SY <--
|
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val columns by presenter.getColumnsPreferenceForCurrentOrientation()
|
||||||
|
|
||||||
BrowseSourceScreen(
|
val mangaList = presenter.getMangaList().collectAsLazyPagingItems()
|
||||||
presenter = presenter,
|
|
||||||
navigateUp = navigateUp,
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
onDisplayModeChange = { presenter.displayMode = (it) },
|
|
||||||
onFabClick = onFabClick,
|
val uriHandler = LocalUriHandler.current
|
||||||
onMangaClick = onClickManga,
|
|
||||||
onMangaLongClick = onClickManga,
|
val onHelpClick = {
|
||||||
onWebViewClick = f@{
|
uriHandler.openUri(LocalSource.HELP_URL)
|
||||||
val source = presenter.source as? HttpSource ?: return@f
|
}
|
||||||
val intent = WebViewActivity.newIntent(context, source.baseUrl, source.id, source.name)
|
|
||||||
context.startActivity(intent)
|
Scaffold(
|
||||||
|
topBar = { scrollBehavior ->
|
||||||
|
BrowseSourceSearchToolbar(
|
||||||
|
searchQuery = presenter.searchQuery ?: "",
|
||||||
|
onSearchQueryChanged = { presenter.searchQuery = it },
|
||||||
|
navigateUp = navigateUp,
|
||||||
|
onResetClick = { presenter.searchQuery = "" },
|
||||||
|
onSearchClick = { presenter.search() },
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
// SY -->
|
floatingActionButton = {
|
||||||
onSettingsClick = onSettingsClick,
|
BrowseSourceFloatingActionButton(
|
||||||
// SY <--
|
isVisible = presenter.filters.isNotEmpty(),
|
||||||
)
|
onFabClick = onFabClick,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
snackbarHost = {
|
||||||
|
SnackbarHost(hostState = snackbarHostState)
|
||||||
|
},
|
||||||
|
) { paddingValues ->
|
||||||
|
BrowseSourceContent(
|
||||||
|
state = presenter,
|
||||||
|
mangaList = mangaList,
|
||||||
|
getMangaState = { presenter.getManga(it) },
|
||||||
|
// SY -->
|
||||||
|
getMetadataState = { manga, metadata ->
|
||||||
|
presenter.getRaisedSearchMetadata(manga, metadata)
|
||||||
|
},
|
||||||
|
// SY <--
|
||||||
|
columns = columns,
|
||||||
|
// SY -->
|
||||||
|
ehentaiBrowseDisplayMode = presenter.ehentaiBrowseDisplayMode,
|
||||||
|
// SY <--
|
||||||
|
displayMode = presenter.displayMode,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
contentPadding = paddingValues,
|
||||||
|
onWebViewClick = onWebViewClick,
|
||||||
|
onHelpClick = { uriHandler.openUri(MoreController.URL_HELP) },
|
||||||
|
onLocalSourceHelpClick = onHelpClick,
|
||||||
|
onMangaClick = onMangaClick,
|
||||||
|
onMangaLongClick = onMangaClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.domain.source.model.Pin
|
import eu.kanade.domain.source.model.Pin
|
||||||
import eu.kanade.domain.source.model.Source
|
import eu.kanade.domain.source.model.Source
|
||||||
import eu.kanade.presentation.browse.components.BaseSourceItem
|
import eu.kanade.presentation.browse.components.BaseSourceItem
|
||||||
@ -50,9 +51,8 @@ import kotlinx.coroutines.flow.collectLatest
|
|||||||
@Composable
|
@Composable
|
||||||
fun SourcesScreen(
|
fun SourcesScreen(
|
||||||
presenter: SourcesPresenter,
|
presenter: SourcesPresenter,
|
||||||
onClickItem: (Source) -> Unit,
|
onClickItem: (Source, String) -> Unit,
|
||||||
onClickDisable: (Source) -> Unit,
|
onClickDisable: (Source) -> Unit,
|
||||||
onClickLatest: (Source) -> Unit,
|
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
onClickSetCategories: (Source, List<String>) -> Unit,
|
onClickSetCategories: (Source, List<String>) -> Unit,
|
||||||
onClickToggleDataSaver: (Source) -> Unit,
|
onClickToggleDataSaver: (Source) -> Unit,
|
||||||
@ -66,7 +66,6 @@ fun SourcesScreen(
|
|||||||
state = presenter,
|
state = presenter,
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onClickDisable = onClickDisable,
|
onClickDisable = onClickDisable,
|
||||||
onClickLatest = onClickLatest,
|
|
||||||
onClickPin = onClickPin,
|
onClickPin = onClickPin,
|
||||||
onClickSetCategories = onClickSetCategories,
|
onClickSetCategories = onClickSetCategories,
|
||||||
onClickToggleDataSaver = onClickToggleDataSaver,
|
onClickToggleDataSaver = onClickToggleDataSaver,
|
||||||
@ -87,9 +86,8 @@ fun SourcesScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
fun SourceList(
|
fun SourceList(
|
||||||
state: SourcesState,
|
state: SourcesState,
|
||||||
onClickItem: (Source) -> Unit,
|
onClickItem: (Source, String) -> Unit,
|
||||||
onClickDisable: (Source) -> Unit,
|
onClickDisable: (Source) -> Unit,
|
||||||
onClickLatest: (Source) -> Unit,
|
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
onClickSetCategories: (Source, List<String>) -> Unit,
|
onClickSetCategories: (Source, List<String>) -> Unit,
|
||||||
onClickToggleDataSaver: (Source) -> Unit,
|
onClickToggleDataSaver: (Source) -> Unit,
|
||||||
@ -127,7 +125,6 @@ fun SourceList(
|
|||||||
showPin = state.showPin,
|
showPin = state.showPin,
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onLongClickItem = { state.dialog = Dialog.SourceLongClick(it) },
|
onLongClickItem = { state.dialog = Dialog.SourceLongClick(it) },
|
||||||
onClickLatest = onClickLatest,
|
|
||||||
onClickPin = onClickPin,
|
onClickPin = onClickPin,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -199,19 +196,18 @@ fun SourceItem(
|
|||||||
showLatest: Boolean,
|
showLatest: Boolean,
|
||||||
showPin: Boolean,
|
showPin: Boolean,
|
||||||
// SY <--
|
// SY <--
|
||||||
onClickItem: (Source) -> Unit,
|
onClickItem: (Source, String) -> Unit,
|
||||||
onLongClickItem: (Source) -> Unit,
|
onLongClickItem: (Source) -> Unit,
|
||||||
onClickLatest: (Source) -> Unit,
|
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
) {
|
) {
|
||||||
BaseSourceItem(
|
BaseSourceItem(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
source = source,
|
source = source,
|
||||||
onClickItem = { onClickItem(source) },
|
onClickItem = { onClickItem(source, GetRemoteManga.QUERY_POPULAR) },
|
||||||
onLongClickItem = { onLongClickItem(source) },
|
onLongClickItem = { onLongClickItem(source) },
|
||||||
action = { source ->
|
action = { source ->
|
||||||
if (source.supportsLatest /* SY --> */ && showLatest /* SY <-- */) {
|
if (source.supportsLatest /* SY --> */ && showLatest /* SY <-- */) {
|
||||||
TextButton(onClick = { onClickLatest(source) }) {
|
TextButton(onClick = { onClickItem(source, GetRemoteManga.QUERY_LATEST) }) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.latest),
|
text = stringResource(R.string.latest),
|
||||||
style = LocalTextStyle.current.copy(
|
style = LocalTextStyle.current.copy(
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
package eu.kanade.presentation.browse.components
|
|
||||||
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ViewModule
|
|
||||||
import androidx.compose.material.icons.outlined.Check
|
|
||||||
import androidx.compose.material.icons.outlined.Help
|
|
||||||
import androidx.compose.material.icons.outlined.Public
|
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import eu.kanade.presentation.components.AppBar
|
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
|
||||||
import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode
|
|
||||||
import exh.source.anyIs
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BrowseLatestToolbar(
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
source: CatalogueSource,
|
|
||||||
displayMode: LibraryDisplayMode?,
|
|
||||||
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
|
|
||||||
onHelpClick: () -> Unit,
|
|
||||||
onWebViewClick: () -> Unit,
|
|
||||||
// SY -->
|
|
||||||
onSettingsClick: () -> Unit,
|
|
||||||
// SY <--
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
|
||||||
) {
|
|
||||||
AppBar(
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
title = source.name,
|
|
||||||
actions = {
|
|
||||||
var selectingDisplayMode by remember { mutableStateOf(false) }
|
|
||||||
AppBarActions(
|
|
||||||
// SY -->
|
|
||||||
actions = listOfNotNull(
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(id = R.string.action_display_mode),
|
|
||||||
icon = Icons.Filled.ViewModule,
|
|
||||||
onClick = { selectingDisplayMode = true },
|
|
||||||
).takeIf { displayMode != null },
|
|
||||||
// SY <--
|
|
||||||
if (source is LocalSource) {
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(id = R.string.label_help),
|
|
||||||
icon = Icons.Outlined.Help,
|
|
||||||
onClick = onHelpClick,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(id = R.string.action_web_view),
|
|
||||||
icon = Icons.Outlined.Public,
|
|
||||||
onClick = onWebViewClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
// SY -->
|
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(R.string.action_settings),
|
|
||||||
icon = Icons.Outlined.Settings,
|
|
||||||
onClick = onSettingsClick,
|
|
||||||
).takeIf { source.anyIs<ConfigurableSource>() },
|
|
||||||
// SY <--
|
|
||||||
),
|
|
||||||
)
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = selectingDisplayMode,
|
|
||||||
onDismissRequest = { selectingDisplayMode = false },
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(id = R.string.action_display_comfortable_grid)) },
|
|
||||||
onClick = { onDisplayModeChange(LibraryDisplayMode.ComfortableGrid) },
|
|
||||||
trailingIcon = {
|
|
||||||
if (displayMode == LibraryDisplayMode.ComfortableGrid) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Check,
|
|
||||||
contentDescription = "",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(id = R.string.action_display_grid)) },
|
|
||||||
onClick = { onDisplayModeChange(LibraryDisplayMode.CompactGrid) },
|
|
||||||
trailingIcon = {
|
|
||||||
if (displayMode == LibraryDisplayMode.CompactGrid) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Check,
|
|
||||||
contentDescription = "",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(id = R.string.action_display_list)) },
|
|
||||||
onClick = { onDisplayModeChange(LibraryDisplayMode.List) },
|
|
||||||
trailingIcon = {
|
|
||||||
if (displayMode == LibraryDisplayMode.List) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Check,
|
|
||||||
contentDescription = "",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
}
|
|
@ -37,6 +37,7 @@ fun BrowseSourceComfortableGrid(
|
|||||||
// SY -->
|
// SY -->
|
||||||
getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State<RaisedSearchMetadata?>),
|
getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State<RaisedSearchMetadata?>),
|
||||||
// SY <--
|
// SY <--
|
||||||
|
header: (@Composable () -> Unit)? = null,
|
||||||
columns: GridCells,
|
columns: GridCells,
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
onMangaClick: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
@ -44,12 +45,18 @@ fun BrowseSourceComfortableGrid(
|
|||||||
) {
|
) {
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = columns,
|
columns = columns,
|
||||||
contentPadding = PaddingValues(8.dp) + contentPadding,
|
contentPadding = PaddingValues(8.dp, 4.dp) + contentPadding,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
if (header != null) {
|
||||||
if (mangaList.loadState.prepend is LoadState.Loading) {
|
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||||
|
header()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mangaList.loadState.prepend is LoadState.Loading) {
|
||||||
|
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||||
BrowseSourceLoadingItem()
|
BrowseSourceLoadingItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,8 +77,8 @@ fun BrowseSourceComfortableGrid(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
if (mangaList.loadState.refresh is LoadState.Loading || mangaList.loadState.append is LoadState.Loading) {
|
||||||
if (mangaList.loadState.refresh is LoadState.Loading || mangaList.loadState.append is LoadState.Loading) {
|
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||||
BrowseSourceLoadingItem()
|
BrowseSourceLoadingItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,13 +48,20 @@ fun BrowseSourceCompactGrid(
|
|||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
onMangaClick: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
onMangaLongClick: (Manga) -> Unit,
|
||||||
|
header: (@Composable () -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = columns,
|
columns = columns,
|
||||||
contentPadding = PaddingValues(8.dp) + contentPadding,
|
contentPadding = PaddingValues(8.dp, 4.dp) + contentPadding,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
|
if (header != null) {
|
||||||
|
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||||
|
header()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||||
if (mangaList.loadState.prepend is LoadState.Loading) {
|
if (mangaList.loadState.prepend is LoadState.Loading) {
|
||||||
BrowseSourceLoadingItem()
|
BrowseSourceLoadingItem()
|
||||||
|
@ -58,10 +58,17 @@ fun BrowseSourceEHentaiList(
|
|||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
onMangaClick: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
onMangaLongClick: (Manga) -> Unit,
|
||||||
|
header: (@Composable () -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
|
if (header != null) {
|
||||||
|
item {
|
||||||
|
header()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
if (mangaList.loadState.prepend is LoadState.Loading) {
|
if (mangaList.loadState.prepend is LoadState.Loading) {
|
||||||
BrowseSourceLoadingItem()
|
BrowseSourceLoadingItem()
|
||||||
|
@ -36,10 +36,17 @@ fun BrowseSourceList(
|
|||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
onMangaClick: (Manga) -> Unit,
|
onMangaClick: (Manga) -> Unit,
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
onMangaLongClick: (Manga) -> Unit,
|
||||||
|
header: (@Composable () -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
|
if (header != null) {
|
||||||
|
item {
|
||||||
|
header()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
if (mangaList.loadState.prepend is LoadState.Loading) {
|
if (mangaList.loadState.prepend is LoadState.Loading) {
|
||||||
BrowseSourceLoadingItem()
|
BrowseSourceLoadingItem()
|
||||||
|
@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -18,8 +17,6 @@ fun BrowseSourceLoadingItem() {
|
|||||||
.padding(vertical = 16.dp),
|
.padding(vertical = 16.dp),
|
||||||
horizontalArrangement = Arrangement.Center,
|
horizontalArrangement = Arrangement.Center,
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator()
|
||||||
modifier = Modifier.size(64.dp),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,15 @@ fun BrowseSourceToolbar(
|
|||||||
) {
|
) {
|
||||||
if (state.searchQuery == null) {
|
if (state.searchQuery == null) {
|
||||||
BrowseSourceRegularToolbar(
|
BrowseSourceRegularToolbar(
|
||||||
source = source,
|
title = if (state.isUserQuery) state.currentQuery else source.name,
|
||||||
|
isLocalSource = source is LocalSource,
|
||||||
|
// SY -->
|
||||||
|
isConfigurableSource = source.anyIs<ConfigurableSource>(),
|
||||||
|
// SY <--
|
||||||
displayMode = displayMode,
|
displayMode = displayMode,
|
||||||
onDisplayModeChange = onDisplayModeChange,
|
onDisplayModeChange = onDisplayModeChange,
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
onSearchClick = { state.searchQuery = "" },
|
onSearchClick = { state.searchQuery = if (state.isUserQuery) state.currentQuery else "" },
|
||||||
onWebViewClick = onWebViewClick,
|
onWebViewClick = onWebViewClick,
|
||||||
onHelpClick = onHelpClick,
|
onHelpClick = onHelpClick,
|
||||||
// SY -->
|
// SY -->
|
||||||
@ -65,10 +69,7 @@ fun BrowseSourceToolbar(
|
|||||||
BrowseSourceSearchToolbar(
|
BrowseSourceSearchToolbar(
|
||||||
searchQuery = state.searchQuery!!,
|
searchQuery = state.searchQuery!!,
|
||||||
onSearchQueryChanged = { state.searchQuery = it },
|
onSearchQueryChanged = { state.searchQuery = it },
|
||||||
navigateUp = {
|
navigateUp = { state.searchQuery = null },
|
||||||
state.searchQuery = null
|
|
||||||
onSearch()
|
|
||||||
},
|
|
||||||
onResetClick = { state.searchQuery = "" },
|
onResetClick = { state.searchQuery = "" },
|
||||||
onSearchClick = onSearch,
|
onSearchClick = onSearch,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
@ -78,7 +79,9 @@ fun BrowseSourceToolbar(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BrowseSourceRegularToolbar(
|
fun BrowseSourceRegularToolbar(
|
||||||
source: CatalogueSource,
|
title: String,
|
||||||
|
isLocalSource: Boolean,
|
||||||
|
isConfigurableSource: Boolean,
|
||||||
displayMode: LibraryDisplayMode?,
|
displayMode: LibraryDisplayMode?,
|
||||||
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
|
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
@ -92,7 +95,7 @@ fun BrowseSourceRegularToolbar(
|
|||||||
) {
|
) {
|
||||||
AppBar(
|
AppBar(
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = source.name,
|
title = title,
|
||||||
actions = {
|
actions = {
|
||||||
var selectingDisplayMode by remember { mutableStateOf(false) }
|
var selectingDisplayMode by remember { mutableStateOf(false) }
|
||||||
AppBarActions(
|
AppBarActions(
|
||||||
@ -109,7 +112,7 @@ fun BrowseSourceRegularToolbar(
|
|||||||
onClick = { selectingDisplayMode = true },
|
onClick = { selectingDisplayMode = true },
|
||||||
).takeIf { displayMode != null },
|
).takeIf { displayMode != null },
|
||||||
// SY <--
|
// SY <--
|
||||||
if (source is LocalSource) {
|
if (isLocalSource) {
|
||||||
AppBar.Action(
|
AppBar.Action(
|
||||||
title = stringResource(id = R.string.label_help),
|
title = stringResource(id = R.string.label_help),
|
||||||
icon = Icons.Outlined.Help,
|
icon = Icons.Outlined.Help,
|
||||||
@ -123,11 +126,13 @@ fun BrowseSourceRegularToolbar(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
// SY -->
|
// SY -->
|
||||||
AppBar.Action(
|
if (isConfigurableSource) {
|
||||||
title = stringResource(R.string.action_settings),
|
AppBar.Action(
|
||||||
icon = Icons.Outlined.Settings,
|
title = stringResource(R.string.action_settings),
|
||||||
onClick = onSettingsClick,
|
icon = Icons.Outlined.Settings,
|
||||||
).takeIf { source.anyIs<ConfigurableSource>() },
|
onClick = onSettingsClick,
|
||||||
|
)
|
||||||
|
} else null,
|
||||||
// SY <--
|
// SY <--
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3,4 +3,12 @@ package eu.kanade.tachiyomi.source.model
|
|||||||
data class FilterList(val list: List<Filter<*>>) : List<Filter<*>> by list {
|
data class FilterList(val list: List<Filter<*>>) : List<Filter<*>> by list {
|
||||||
|
|
||||||
constructor(vararg fs: Filter<*>) : this(if (fs.isNotEmpty()) fs.asList() else emptyList())
|
constructor(vararg fs: Filter<*>) : this(if (fs.isNotEmpty()) fs.asList() else emptyList())
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return list.hashCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,13 @@ import androidx.compose.material.icons.outlined.Add
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.presentation.browse.FeedScreen
|
import eu.kanade.presentation.browse.FeedScreen
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.TabContent
|
import eu.kanade.presentation.components.TabContent
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -44,7 +44,7 @@ fun feedTab(
|
|||||||
},
|
},
|
||||||
onClickSource = { source ->
|
onClickSource = { source ->
|
||||||
presenter.preferences.lastUsedSource().set(source.id)
|
presenter.preferences.lastUsedSource().set(source.id)
|
||||||
router?.pushController(LatestUpdatesController(source))
|
router?.pushController(BrowseSourceController(source, GetRemoteManga.QUERY_LATEST))
|
||||||
},
|
},
|
||||||
onClickDelete = {
|
onClickDelete = {
|
||||||
presenter.dialog = FeedPresenter.Dialog.DeleteFeed(it)
|
presenter.dialog = FeedPresenter.Dialog.DeleteFeed(it)
|
||||||
|
@ -8,10 +8,10 @@ import eu.kanade.domain.manga.model.Manga
|
|||||||
import eu.kanade.presentation.browse.SourceSearchScreen
|
import eu.kanade.presentation.browse.SourceSearchScreen
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesController
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
|
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||||
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -31,12 +31,16 @@ class SourceSearchController(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun ComposeContent() {
|
override fun ComposeContent() {
|
||||||
|
// LocalContext is not a first available to us when we try access it
|
||||||
|
// Decoupling from BrowseSourceController is needed
|
||||||
|
val context = applicationContext!!
|
||||||
|
|
||||||
SourceSearchScreen(
|
SourceSearchScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
navigateUp = { router.popCurrentController() },
|
navigateUp = { router.popCurrentController() },
|
||||||
onFabClick = { filterSheet?.show() },
|
onFabClick = { filterSheet?.show() },
|
||||||
// SY -->
|
// SY -->
|
||||||
onClickManga = { manga ->
|
onMangaClick = { manga ->
|
||||||
val migrationListController = targetController as? MigrationListController ?: return@SourceSearchScreen
|
val migrationListController = targetController as? MigrationListController ?: return@SourceSearchScreen
|
||||||
val sourceManager = Injekt.get<SourceManager>()
|
val sourceManager = Injekt.get<SourceManager>()
|
||||||
val source = sourceManager.get(manga.source) ?: return@SourceSearchScreen
|
val source = sourceManager.get(manga.source) ?: return@SourceSearchScreen
|
||||||
@ -44,10 +48,12 @@ class SourceSearchController(
|
|||||||
router.popCurrentController()
|
router.popCurrentController()
|
||||||
router.popCurrentController()
|
router.popCurrentController()
|
||||||
},
|
},
|
||||||
onSettingsClick = {
|
|
||||||
router.pushController(SourcePreferencesController(presenter.source!!.id))
|
|
||||||
},
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
onWebViewClick = f@{
|
||||||
|
val source = presenter.source as? HttpSource ?: return@f
|
||||||
|
val intent = WebViewActivity.newIntent(context, source.baseUrl, source.id, source.name)
|
||||||
|
context.startActivity(intent)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(presenter.filters) {
|
LaunchedEffect(presenter.filters) {
|
||||||
|
@ -6,6 +6,7 @@ import androidx.compose.material.icons.outlined.TravelExplore
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga.Companion.QUERY_POPULAR
|
||||||
import eu.kanade.presentation.browse.SourcesScreen
|
import eu.kanade.presentation.browse.SourcesScreen
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.TabContent
|
import eu.kanade.presentation.components.TabContent
|
||||||
@ -14,7 +15,6 @@ import eu.kanade.tachiyomi.ui.base.controller.pushController
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedController
|
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController
|
|
||||||
import exh.ui.smartsearch.SmartSearchController
|
import exh.ui.smartsearch.SmartSearchController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -45,13 +45,13 @@ fun sourcesTab(
|
|||||||
content = {
|
content = {
|
||||||
SourcesScreen(
|
SourcesScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
onClickItem = { source ->
|
onClickItem = { source, query ->
|
||||||
// SY -->
|
// SY -->
|
||||||
val controller = when {
|
val controller = when {
|
||||||
presenter.controllerMode == SourcesController.Mode.SMART_SEARCH ->
|
presenter.controllerMode == SourcesController.Mode.SMART_SEARCH ->
|
||||||
SmartSearchController(source.id, presenter.smartSearchConfig!!)
|
SmartSearchController(source.id, presenter.smartSearchConfig!!)
|
||||||
presenter.useNewSourceNavigation -> SourceFeedController(source.id)
|
(query.isBlank() || query == QUERY_POPULAR) && presenter.useNewSourceNavigation -> SourceFeedController(source.id)
|
||||||
else -> BrowseSourceController(source)
|
else -> BrowseSourceController(source, query)
|
||||||
}
|
}
|
||||||
presenter.onOpenSource(source)
|
presenter.onOpenSource(source)
|
||||||
router?.pushController(controller)
|
router?.pushController(controller)
|
||||||
@ -60,10 +60,6 @@ fun sourcesTab(
|
|||||||
onClickDisable = { source ->
|
onClickDisable = { source ->
|
||||||
presenter.toggleSource(source)
|
presenter.toggleSource(source)
|
||||||
},
|
},
|
||||||
onClickLatest = { source ->
|
|
||||||
presenter.onOpenSource(source)
|
|
||||||
router?.pushController(LatestUpdatesController(source))
|
|
||||||
},
|
|
||||||
onClickPin = { source ->
|
onClickPin = { source ->
|
||||||
presenter.togglePin(source)
|
presenter.togglePin(source)
|
||||||
},
|
},
|
||||||
|
@ -102,6 +102,17 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||||||
*/
|
*/
|
||||||
protected var filterSheet: SourceFilterSheet? = null
|
protected var filterSheet: SourceFilterSheet? = null
|
||||||
|
|
||||||
|
override fun createPresenter(): BrowseSourcePresenter {
|
||||||
|
// SY -->
|
||||||
|
return BrowseSourcePresenter(
|
||||||
|
args.getLong(SOURCE_ID_KEY),
|
||||||
|
args.getString(SEARCH_QUERY_KEY),
|
||||||
|
filtersJson = args.getString(FILTERS_CONFIG_KEY),
|
||||||
|
savedSearch = args.getLong(SAVED_SEARCH_CONFIG_KEY, 0).takeUnless { it == 0L },
|
||||||
|
)
|
||||||
|
// SY <--
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun ComposeContent() {
|
override fun ComposeContent() {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@ -110,7 +121,6 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||||||
BrowseSourceScreen(
|
BrowseSourceScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
navigateUp = { router.popCurrentController() },
|
navigateUp = { router.popCurrentController() },
|
||||||
onDisplayModeChange = { presenter.displayMode = (it) },
|
|
||||||
onFabClick = { filterSheet?.show() },
|
onFabClick = { filterSheet?.show() },
|
||||||
onMangaClick = { router.pushController(MangaController(it.id, true)) },
|
onMangaClick = { router.pushController(MangaController(it.id, true)) },
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = { manga ->
|
||||||
@ -174,17 +184,6 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createPresenter(): BrowseSourcePresenter {
|
|
||||||
// SY -->
|
|
||||||
return BrowseSourcePresenter(
|
|
||||||
args.getLong(SOURCE_ID_KEY),
|
|
||||||
args.getString(SEARCH_QUERY_KEY),
|
|
||||||
filtersJson = args.getString(FILTERS_CONFIG_KEY),
|
|
||||||
savedSearch = args.getLong(SAVED_SEARCH_CONFIG_KEY, 0).takeUnless { it == 0L },
|
|
||||||
)
|
|
||||||
// SY <--
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSavedSearches(savedSearches: List<EXHSavedSearch>) {
|
fun setSavedSearches(savedSearches: List<EXHSavedSearch>) {
|
||||||
filterSheet?.setSavedSearches(savedSearches)
|
filterSheet?.setSavedSearches(savedSearches)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import androidx.paging.map
|
import androidx.paging.map
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
@ -33,7 +32,9 @@ import eu.kanade.domain.manga.model.toDbManga
|
|||||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||||
import eu.kanade.domain.source.interactor.DeleteSavedSearchById
|
import eu.kanade.domain.source.interactor.DeleteSavedSearchById
|
||||||
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.domain.source.interactor.InsertSavedSearch
|
import eu.kanade.domain.source.interactor.InsertSavedSearch
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.domain.track.interactor.InsertTrack
|
import eu.kanade.domain.track.interactor.InsertTrack
|
||||||
import eu.kanade.domain.track.model.toDomainTrack
|
import eu.kanade.domain.track.model.toDomainTrack
|
||||||
import eu.kanade.presentation.browse.BrowseSourceState
|
import eu.kanade.presentation.browse.BrowseSourceState
|
||||||
@ -77,7 +78,6 @@ import eu.kanade.tachiyomi.util.system.logcat
|
|||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.savedsearches.models.SavedSearch
|
import exh.savedsearches.models.SavedSearch
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
import exh.source.isEhBasedSource
|
|
||||||
import exh.util.nullIfBlank
|
import exh.util.nullIfBlank
|
||||||
import kotlinx.coroutines.NonCancellable
|
import kotlinx.coroutines.NonCancellable
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -112,6 +112,7 @@ open class BrowseSourcePresenter(
|
|||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val preferences: PreferencesHelper = Injekt.get(),
|
private val preferences: PreferencesHelper = Injekt.get(),
|
||||||
private val coverCache: CoverCache = Injekt.get(),
|
private val coverCache: CoverCache = Injekt.get(),
|
||||||
|
private val getRemoteManga: GetRemoteManga = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
@ -130,6 +131,8 @@ open class BrowseSourcePresenter(
|
|||||||
// SY <--
|
// SY <--
|
||||||
) : BasePresenter<BrowseSourceController>(), BrowseSourceState by state {
|
) : BasePresenter<BrowseSourceController>(), BrowseSourceState by state {
|
||||||
|
|
||||||
|
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||||
|
|
||||||
var displayMode by preferences.sourceDisplayMode().asState()
|
var displayMode by preferences.sourceDisplayMode().asState()
|
||||||
|
|
||||||
val ehentaiBrowseDisplayMode by preferences.enhancedEHentaiView().asState()
|
val ehentaiBrowseDisplayMode by preferences.enhancedEHentaiView().asState()
|
||||||
@ -148,11 +151,11 @@ open class BrowseSourcePresenter(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getMangaList(): Flow<PagingData</* SY --> */Pair<DomainManga, RaisedSearchMetadata?>/* SY <-- */>> {
|
fun getMangaList(): Flow<PagingData</* SY --> */Pair<DomainManga, RaisedSearchMetadata?>/* SY <-- */>> {
|
||||||
return remember(currentQuery, appliedFilters) {
|
return remember(currentQuery, currentFilters) {
|
||||||
Pager(
|
Pager(
|
||||||
PagingConfig(pageSize = 25),
|
PagingConfig(pageSize = 25),
|
||||||
) {
|
) {
|
||||||
createPager(currentQuery, appliedFilters)
|
createSourcePagingSource(currentQuery, currentFilters)
|
||||||
}.flow
|
}.flow
|
||||||
.map {
|
.map {
|
||||||
it.map {
|
it.map {
|
||||||
@ -169,12 +172,12 @@ open class BrowseSourcePresenter(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getManga(initialManga: DomainManga): State<DomainManga> {
|
fun getManga(initialManga: DomainManga): State<DomainManga> {
|
||||||
return produceState(initialValue = initialManga, initialManga.url, initialManga.source) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
if (manga == null) return@collectLatest
|
if (manga == null) return@collectLatest
|
||||||
launchIO {
|
withIOContext {
|
||||||
initializeMangas(manga)
|
initializeManga(manga)
|
||||||
}
|
}
|
||||||
value = manga
|
value = manga
|
||||||
}
|
}
|
||||||
@ -198,17 +201,15 @@ open class BrowseSourcePresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun resetFilter() {
|
fun resetFilter() {
|
||||||
state.appliedFilters = FilterList()
|
|
||||||
val newFilters = source!!.getFilterList()
|
val newFilters = source!!.getFilterList()
|
||||||
state.filters = newFilters
|
state.filters = newFilters
|
||||||
|
state.currentFilters = state.filters
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search() {
|
fun search(query: String? = null) {
|
||||||
state.currentQuery = searchQuery ?: ""
|
state.currentQuery = query ?: searchQuery ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private val filterSerializer = FilterSerializer()
|
private val filterSerializer = FilterSerializer()
|
||||||
// SY <--
|
// SY <--
|
||||||
@ -246,15 +247,6 @@ open class BrowseSourcePresenter(
|
|||||||
}
|
}
|
||||||
.launchIn(presenterScope)
|
.launchIn(presenterScope)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
if (savedState != null) {
|
|
||||||
query = savedState.getString(::query.name, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSave(state: Bundle) {
|
|
||||||
state.putString(::query.name, query)
|
|
||||||
super.onSave(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,9 +276,9 @@ open class BrowseSourcePresenter(
|
|||||||
/**
|
/**
|
||||||
* Initialize a manga.
|
* Initialize a manga.
|
||||||
*
|
*
|
||||||
* @param mangas the list of manga to initialize.
|
* @param manga to initialize.
|
||||||
*/
|
*/
|
||||||
private suspend fun initializeMangas(manga: DomainManga) {
|
private suspend fun initializeManga(manga: DomainManga) {
|
||||||
if (manga.thumbnailUrl != null && manga.initialized) return
|
if (manga.thumbnailUrl != null && manga.initialized) return
|
||||||
withContext(NonCancellable) {
|
withContext(NonCancellable) {
|
||||||
val db = manga.toDbManga()
|
val db = manga.toDbManga()
|
||||||
@ -394,18 +386,14 @@ open class BrowseSourcePresenter(
|
|||||||
* @param filters a list of active filters.
|
* @param filters a list of active filters.
|
||||||
*/
|
*/
|
||||||
fun setSourceFilter(filters: FilterList) {
|
fun setSourceFilter(filters: FilterList) {
|
||||||
state.appliedFilters = filters
|
state.currentFilters = filters
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun createPager(query: String, filters: FilterList): PagingSource<Long, Pair<SManga, RaisedSearchMetadata?>> {
|
// SY -->
|
||||||
// SY -->
|
open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||||
return if (source!!.isEhBasedSource()) {
|
return getRemoteManga.subscribe(sourceId, currentQuery, currentFilters)
|
||||||
EHentaiBrowsePagingSource(source!!, query, filters)
|
|
||||||
} else {
|
|
||||||
SourceBrowsePagingSource(source!!, query, filters)
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
}
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user categories.
|
* Get user categories.
|
||||||
@ -423,12 +411,6 @@ open class BrowseSourcePresenter(
|
|||||||
return getDuplicateLibraryManga.await(manga.title, manga.source)
|
return getDuplicateLibraryManga.await(manga.title, manga.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the given manga to categories.
|
|
||||||
*
|
|
||||||
* @param categories the selected categories.
|
|
||||||
* @param manga the manga to move.
|
|
||||||
*/
|
|
||||||
fun moveMangaToCategories(manga: DomainManga, vararg categories: DomainCategory) {
|
fun moveMangaToCategories(manga: DomainManga, vararg categories: DomainCategory) {
|
||||||
moveMangaToCategories(manga, categories.filter { it.id != 0L }.map { it.id })
|
moveMangaToCategories(manga, categories.filter { it.id != 0L }.map { it.id })
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
|
||||||
|
|
||||||
class NoResultsException : Exception()
|
|
@ -1,20 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
|
||||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
|
||||||
|
|
||||||
class SourceBrowsePagingSource(val source: CatalogueSource, val query: String, val filters: FilterList) : BrowsePagingSource() {
|
|
||||||
|
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
|
||||||
val observable = if (query.isBlank() && filters.isEmpty()) {
|
|
||||||
source.fetchPopularManga(currentPage)
|
|
||||||
} else {
|
|
||||||
source.fetchSearchManga(currentPage, query, filters)
|
|
||||||
}
|
|
||||||
|
|
||||||
return observable.awaitSingle()
|
|
||||||
.takeIf { it.mangas.isNotEmpty() } ?: throw NoResultsException()
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,6 +8,7 @@ import androidx.core.view.isVisible
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.presentation.browse.SourceFeedScreen
|
import eu.kanade.presentation.browse.SourceFeedScreen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
@ -18,7 +19,6 @@ import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.SourceFilterSheet
|
import eu.kanade.tachiyomi.ui.browse.source.browse.SourceFilterSheet
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
@ -223,11 +223,11 @@ open class SourceFeedController :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onLatestClick() {
|
private fun onLatestClick() {
|
||||||
router.replaceTopController(LatestUpdatesController(presenter.source).withFadeTransaction())
|
router.replaceTopController(BrowseSourceController(presenter.source, GetRemoteManga.QUERY_LATEST).withFadeTransaction())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onBrowseClick() {
|
private fun onBrowseClick() {
|
||||||
router.replaceTopController(BrowseSourceController(presenter.source).withFadeTransaction())
|
router.replaceTopController(BrowseSourceController(presenter.source, GetRemoteManga.QUERY_POPULAR).withFadeTransaction())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSavedSearchClick(savedSearch: SavedSearch) {
|
private fun onSavedSearchClick(savedSearch: SavedSearch) {
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.latest
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowsePagingSource
|
|
||||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
|
||||||
|
|
||||||
class LatestUpdatesBrowsePagingSource(val source: CatalogueSource) : BrowsePagingSource() {
|
|
||||||
|
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
|
||||||
return source.fetchLatestUpdates(currentPage).awaitSingle()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.latest
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import eu.kanade.domain.source.model.Source
|
|
||||||
import eu.kanade.presentation.browse.BrowseLatestScreen
|
|
||||||
import eu.kanade.presentation.browse.components.RemoveMangaDialog
|
|
||||||
import eu.kanade.presentation.components.ChangeCategoryDialog
|
|
||||||
import eu.kanade.presentation.components.DuplicateMangaDialog
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesController
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
|
||||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
|
||||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller that shows the latest manga from the catalogue. Inherit [BrowseSourceController].
|
|
||||||
*/
|
|
||||||
class LatestUpdatesController(bundle: Bundle) : BrowseSourceController(bundle) {
|
|
||||||
|
|
||||||
constructor(source: Source) : this(
|
|
||||||
bundleOf(SOURCE_ID_KEY to source.id),
|
|
||||||
)
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
constructor(source: CatalogueSource) : this(
|
|
||||||
bundleOf(SOURCE_ID_KEY to source.id),
|
|
||||||
)
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
override fun createPresenter(): BrowseSourcePresenter {
|
|
||||||
return LatestUpdatesPresenter(args.getLong(SOURCE_ID_KEY))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun ComposeContent() {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
BrowseLatestScreen(
|
|
||||||
presenter = presenter,
|
|
||||||
navigateUp = { router.popCurrentController() },
|
|
||||||
onMangaClick = { router.pushController(MangaController(it.id, true)) },
|
|
||||||
onMangaLongClick = { manga ->
|
|
||||||
scope.launchIO {
|
|
||||||
val duplicateManga = presenter.getDuplicateLibraryManga(manga)
|
|
||||||
when {
|
|
||||||
manga.favorite -> presenter.dialog = BrowseSourcePresenter.Dialog.RemoveManga(manga)
|
|
||||||
duplicateManga != null -> presenter.dialog = BrowseSourcePresenter.Dialog.AddDuplicateManga(manga, duplicateManga)
|
|
||||||
else -> presenter.addFavorite(manga)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onWebViewClick = f@{
|
|
||||||
val source = presenter.source as? HttpSource ?: return@f
|
|
||||||
val intent = WebViewActivity.newIntent(context, source.baseUrl, source.id, source.name)
|
|
||||||
context.startActivity(intent)
|
|
||||||
},
|
|
||||||
// SY -->
|
|
||||||
onSettingsClick = {
|
|
||||||
router.pushController(SourcePreferencesController(presenter.source!!.id))
|
|
||||||
},
|
|
||||||
// SY <--
|
|
||||||
)
|
|
||||||
|
|
||||||
val onDismissRequest = { presenter.dialog = null }
|
|
||||||
when (val dialog = presenter.dialog) {
|
|
||||||
is BrowseSourcePresenter.Dialog.AddDuplicateManga -> {
|
|
||||||
DuplicateMangaDialog(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
onOpenManga = {
|
|
||||||
router.pushController(MangaController(dialog.duplicate.id, true))
|
|
||||||
},
|
|
||||||
onConfirm = {
|
|
||||||
presenter.addFavorite(dialog.manga)
|
|
||||||
},
|
|
||||||
duplicateFrom = presenter.getSourceOrStub(dialog.manga),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is BrowseSourcePresenter.Dialog.RemoveManga -> {
|
|
||||||
RemoveMangaDialog(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
onConfirm = {
|
|
||||||
presenter.changeMangaFavorite(dialog.manga)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is BrowseSourcePresenter.Dialog.ChangeMangaCategory -> {
|
|
||||||
ChangeCategoryDialog(
|
|
||||||
initialSelection = dialog.initialSelection,
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
onEditCategories = {
|
|
||||||
router.pushController(CategoryController())
|
|
||||||
},
|
|
||||||
onConfirm = { include, _ ->
|
|
||||||
presenter.changeMangaFavorite(dialog.manga)
|
|
||||||
presenter.moveMangaToCategories(dialog.manga, include)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
null -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initFilterSheet() {
|
|
||||||
// No-op: we don't allow filtering in latest
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.latest
|
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
|
||||||
|
|
||||||
class LatestUpdatesPresenter(sourceId: Long) : BrowseSourcePresenter(sourceId) {
|
|
||||||
|
|
||||||
override fun createPager(query: String, filters: FilterList): PagingSource<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?> /*SY <-- */> {
|
|
||||||
return LatestUpdatesBrowsePagingSource(source!!)
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,7 +50,6 @@ import eu.kanade.tachiyomi.ui.browse.source.SourcesController.Companion.SMART_SE
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedController
|
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController
|
|
||||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
@ -483,10 +482,6 @@ class MangaController : FullComposeController<MangaPresenter> {
|
|||||||
val controller = router.getControllerWithTag(R.id.nav_library.toString()) as LibraryController
|
val controller = router.getControllerWithTag(R.id.nav_library.toString()) as LibraryController
|
||||||
controller.search(query)
|
controller.search(query)
|
||||||
}
|
}
|
||||||
is LatestUpdatesController -> {
|
|
||||||
// Search doesn't currently work in source Latest view
|
|
||||||
return
|
|
||||||
}
|
|
||||||
is BrowseSourceController -> {
|
is BrowseSourceController -> {
|
||||||
router.handleBack()
|
router.handleBack()
|
||||||
previousController.searchWithQuery(query)
|
previousController.searchWithQuery(query)
|
||||||
|
@ -45,6 +45,7 @@ import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||||
import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController
|
import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||||
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
|
import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
|
||||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
import eu.kanade.tachiyomi.util.preference.bindTo
|
import eu.kanade.tachiyomi.util.preference.bindTo
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package exh.md.follows
|
package exh.md.follows
|
||||||
|
|
||||||
|
import eu.kanade.data.source.SourcePagingSource
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowsePagingSource
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LatestUpdatesPager inherited from the general Pager.
|
* LatestUpdatesPager inherited from the general Pager.
|
||||||
*/
|
*/
|
||||||
class MangaDexFollowsPagingSource(val source: MangaDex) : BrowsePagingSource() {
|
class MangaDexFollowsPagingSource(val mangadex: MangaDex) : SourcePagingSource(mangadex) {
|
||||||
|
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
return source.fetchFollows(currentPage)
|
return mangadex.fetchFollows(currentPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,9 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
@ -18,7 +17,7 @@ import exh.source.getMainSource
|
|||||||
*/
|
*/
|
||||||
class MangaDexFollowsPresenter(sourceId: Long) : BrowseSourcePresenter(sourceId) {
|
class MangaDexFollowsPresenter(sourceId: Long) : BrowseSourcePresenter(sourceId) {
|
||||||
|
|
||||||
override fun createPager(query: String, filters: FilterList): PagingSource<Long, Pair<SManga, RaisedSearchMetadata?>> {
|
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||||
return MangaDexFollowsPagingSource(source!!.getMainSource() as MangaDex)
|
return MangaDexFollowsPagingSource(source!!.getMainSource() as MangaDex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
package exh.md.similar
|
package exh.md.similar
|
||||||
|
|
||||||
|
import eu.kanade.data.source.NoResultsException
|
||||||
|
import eu.kanade.data.source.SourcePagingSource
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowsePagingSource
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.NoResultsException
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MangaDexSimilarPagingSource inherited from the general Pager.
|
* MangaDexSimilarPagingSource inherited from the general Pager.
|
||||||
*/
|
*/
|
||||||
class MangaDexSimilarPagingSource(val manga: Manga, val source: MangaDex) : BrowsePagingSource() {
|
class MangaDexSimilarPagingSource(val manga: Manga, val mangadex: MangaDex) : SourcePagingSource(mangadex) {
|
||||||
|
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
val mangasPage = coroutineScope {
|
val mangasPage = coroutineScope {
|
||||||
val similarPageDef = async { source.getMangaSimilar(manga.toSManga()) }
|
val similarPageDef = async { mangadex.getMangaSimilar(manga.toSManga()) }
|
||||||
val relatedPageDef = async { source.getMangaRelated(manga.toSManga()) }
|
val relatedPageDef = async { mangadex.getMangaRelated(manga.toSManga()) }
|
||||||
val similarPage = similarPageDef.await()
|
val similarPage = similarPageDef.await()
|
||||||
val relatedPage = relatedPageDef.await()
|
val relatedPage = relatedPageDef.await()
|
||||||
|
|
||||||
|
@ -5,11 +5,10 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import eu.kanade.domain.manga.interactor.GetManga
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
@ -34,7 +33,7 @@ class MangaDexSimilarPresenter(
|
|||||||
this.manga = runBlocking { getManga.await(mangaId) }
|
this.manga = runBlocking { getManga.await(mangaId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createPager(query: String, filters: FilterList): PagingSource<Long, Pair<SManga, RaisedSearchMetadata?>> {
|
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||||
return MangaDexSimilarPagingSource(manga!!, source!!.getMainSource() as MangaDex)
|
return MangaDexSimilarPagingSource(manga!!, source!!.getMainSource() as MangaDex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package exh.recs
|
package exh.recs
|
||||||
|
|
||||||
|
import eu.kanade.data.source.NoResultsException
|
||||||
|
import eu.kanade.data.source.SourcePagingSource
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowsePagingSource
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.NoResultsException
|
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import exh.util.MangaType
|
import exh.util.MangaType
|
||||||
@ -193,10 +194,11 @@ class Anilist : API("https://graphql.anilist.co/") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class RecommendsPagingSource(
|
open class RecommendsPagingSource(
|
||||||
|
source: CatalogueSource,
|
||||||
private val manga: Manga,
|
private val manga: Manga,
|
||||||
private val smart: Boolean = true,
|
private val smart: Boolean = true,
|
||||||
private var preferredApi: API = API.MYANIMELIST,
|
private var preferredApi: API = API.MYANIMELIST,
|
||||||
) : BrowsePagingSource() {
|
) : SourcePagingSource(source) {
|
||||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
if (smart) preferredApi = if (manga.mangaType() != MangaType.TYPE_MANGA) API.ANILIST else preferredApi
|
if (smart) preferredApi = if (manga.mangaType() != MangaType.TYPE_MANGA) API.ANILIST else preferredApi
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package exh.recs
|
package exh.recs
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import eu.kanade.domain.manga.interactor.GetManga
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -28,7 +26,7 @@ class RecommendsPresenter(
|
|||||||
this.manga = runBlocking { getManga.await(mangaId) }
|
this.manga = runBlocking { getManga.await(mangaId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createPager(query: String, filters: FilterList): PagingSource<Long, Pair<SManga, RaisedSearchMetadata?>> {
|
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||||
return RecommendsPagingSource(manga!!)
|
return RecommendsPagingSource(source!!, manga!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -582,6 +582,7 @@
|
|||||||
<string name="action_global_search_hint">Global search…</string>
|
<string name="action_global_search_hint">Global search…</string>
|
||||||
<string name="action_global_search_query">Search for \"%1$s\" globally</string>
|
<string name="action_global_search_query">Search for \"%1$s\" globally</string>
|
||||||
<string name="latest">Latest</string>
|
<string name="latest">Latest</string>
|
||||||
|
<string name="popular">Popular</string>
|
||||||
<string name="browse">Browse</string>
|
<string name="browse">Browse</string>
|
||||||
<string name="local_source_help_guide">Local source guide</string>
|
<string name="local_source_help_guide">Local source guide</string>
|
||||||
<string name="no_pinned_sources">You have no pinned sources</string>
|
<string name="no_pinned_sources">You have no pinned sources</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user