diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/EHentaiBrowsePagingSource.kt b/app/src/main/java/eu/kanade/data/source/EHentaiPagingSource.kt similarity index 58% rename from app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/EHentaiBrowsePagingSource.kt rename to app/src/main/java/eu/kanade/data/source/EHentaiPagingSource.kt index dad23f2d8..6ed51da42 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/EHentaiBrowsePagingSource.kt +++ b/app/src/main/java/eu/kanade/data/source/EHentaiPagingSource.kt @@ -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.model.FilterList @@ -6,20 +6,16 @@ import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage 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 + abstract suspend fun fetchNextPage(currentPage: Int): MangasPage + override suspend fun requestNextPage(currentPage: Int): MangasPage { val lastMangaLink = lastMangaLink - val observable = if (query.isBlank() && filters.isEmpty()) { - source.fetchPopularManga(currentPage) - } else { - source.fetchSearchManga(currentPage, query, filters) - } - - val mangasPage = observable.awaitSingle() + val mangasPage = fetchNextPage(currentPage) mangasPage.mangas.lastOrNull()?.let { 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() + } +} diff --git a/app/src/main/java/eu/kanade/data/source/NoResultsException.kt b/app/src/main/java/eu/kanade/data/source/NoResultsException.kt new file mode 100644 index 000000000..e0eee5fc6 --- /dev/null +++ b/app/src/main/java/eu/kanade/data/source/NoResultsException.kt @@ -0,0 +1,3 @@ +package eu.kanade.data.source + +class NoResultsException : Exception() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowsePagingSource.kt b/app/src/main/java/eu/kanade/data/source/SourcePagingSource.kt similarity index 51% rename from app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowsePagingSource.kt rename to app/src/main/java/eu/kanade/data/source/SourcePagingSource.kt index 85b2bb34b..631203db2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowsePagingSource.kt +++ b/app/src/main/java/eu/kanade/data/source/SourcePagingSource.kt @@ -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 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.MetadataMangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.util.lang.awaitSingle import eu.kanade.tachiyomi.util.lang.withIOContext import exh.metadata.metadata.base.RaisedSearchMetadata -abstract class BrowsePagingSource : PagingSource */ Pair /*SY <-- */>() { +abstract class SourcePagingSource( + protected val source: CatalogueSource, +) : SourcePagingSourceType() { abstract suspend fun requestNextPage(currentPage: Int): MangasPage @@ -18,6 +23,8 @@ abstract class BrowsePagingSource : PagingSource */ Pair */ Pair>): Long? { + override fun getRefreshKey(state: PagingState */ Pair/*SY <-- */>): Long? { return state.anchorPosition?.let { anchorPosition -> val anchorPage = state.closestPageToPosition(anchorPosition) 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() + } +} diff --git a/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt index 743fa0bb9..3bcf1a23b 100644 --- a/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt @@ -2,11 +2,15 @@ package eu.kanade.data.source import eu.kanade.data.DatabaseHandler 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.repository.SourceRepository +import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.model.FilterList import exh.source.MERGED_SOURCE_ID +import exh.source.isEhBasedSource import kotlinx.coroutines.flow.Flow 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) + } } diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 5f4bbc5f1..c5e283d7b 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -51,6 +51,7 @@ import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.repository.MangaRepository import eu.kanade.domain.source.interactor.GetEnabledSources 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.GetSourcesWithNonLibraryManga import eu.kanade.domain.source.interactor.SetMigrateSorting @@ -133,6 +134,7 @@ class DomainModule : InjektModule { addSingletonFactory { SourceDataRepositoryImpl(get()) } addFactory { GetEnabledSources(get(), get()) } addFactory { GetLanguagesWithSources(get(), get()) } + addFactory { GetRemoteManga(get()) } addFactory { GetSourcesWithFavoriteCount(get(), get()) } addFactory { GetSourcesWithNonLibraryManga(get()) } addFactory { SetMigrateSorting(get()) } diff --git a/app/src/main/java/eu/kanade/domain/source/interactor/GetRemoteManga.kt b/app/src/main/java/eu/kanade/domain/source/interactor/GetRemoteManga.kt new file mode 100644 index 000000000..0fefeeee6 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/source/interactor/GetRemoteManga.kt @@ -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" + } +} diff --git a/app/src/main/java/eu/kanade/domain/source/model/SourcePagingSourceType.kt b/app/src/main/java/eu/kanade/domain/source/model/SourcePagingSourceType.kt new file mode 100644 index 000000000..e7199c9f9 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/source/model/SourcePagingSourceType.kt @@ -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 */ Pair/*SY <-- */> diff --git a/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt b/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt index daece063d..c49a04e7d 100644 --- a/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt +++ b/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt @@ -1,7 +1,9 @@ package eu.kanade.domain.source.repository import eu.kanade.domain.source.model.Source +import eu.kanade.domain.source.model.SourcePagingSourceType import eu.kanade.domain.source.model.SourceWithCount +import eu.kanade.tachiyomi.source.model.FilterList import kotlinx.coroutines.flow.Flow interface SourceRepository { @@ -13,4 +15,10 @@ interface SourceRepository { fun getSourcesWithFavoriteCount(): Flow>> fun getSourcesWithNonLibraryManga(): Flow> + + fun search(sourceId: Long, query: String, filterList: FilterList): SourcePagingSourceType + + fun getPopular(sourceId: Long): SourcePagingSourceType + + fun getLatest(sourceId: Long): SourcePagingSourceType } diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseLatestScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseLatestScreen.kt deleted file mode 100644 index 4bdf65d9b..000000000 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseLatestScreen.kt +++ /dev/null @@ -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, - ) - } -} diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseMangadexFollowsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseMangadexFollowsScreen.kt index 6b3c85f71..cc652abea 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseMangadexFollowsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseMangadexFollowsScreen.kt @@ -43,7 +43,7 @@ fun BrowseMangadexFollowsScreen( }, ) { paddingValues -> BrowseSourceContent( - source = presenter.source, + state = presenter, mangaList = mangaList, getMangaState = { presenter.getManga(it) }, // SY --> diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseRecommendationsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseRecommendationsScreen.kt index 721162cd5..16a5f1c1d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseRecommendationsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseRecommendationsScreen.kt @@ -31,7 +31,7 @@ fun BrowseRecommendationsScreen( }, ) { paddingValues -> BrowseSourceContent( - source = presenter.source, + state = presenter, mangaList = presenter.getMangaList().collectAsLazyPagingItems(), getMangaState = { presenter.getManga(it) }, // SY --> diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt index 254b0ad21..34b8f74e1 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -1,10 +1,19 @@ 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.Row import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.rememberScrollState 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.NewReleases +import androidx.compose.material3.FilterChip +import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.Icon import androidx.compose.material3.SnackbarDuration 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.LocalUriHandler import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.paging.LoadState import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems +import eu.kanade.data.source.NoResultsException 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.BrowseSourceCompactGrid 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.components.EmptyScreen import eu.kanade.presentation.components.ExtendedFloatingActionButton +import eu.kanade.presentation.components.LoadingScreen import eu.kanade.presentation.components.Scaffold import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.LocalSource 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.more.MoreController import eu.kanade.tachiyomi.widget.EmptyView @@ -47,7 +58,6 @@ import exh.source.isEhBasedSource fun BrowseSourceScreen( presenter: BrowseSourcePresenter, navigateUp: () -> Unit, - onDisplayModeChange: (LibraryDisplayMode) -> Unit, onFabClick: () -> Unit, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, @@ -74,7 +84,7 @@ fun BrowseSourceScreen( state = presenter, source = presenter.source!!, displayMode = presenter.displayMode.takeUnless { presenter.source!!.isEhBasedSource() && presenter.ehentaiBrowseDisplayMode }, - onDisplayModeChange = onDisplayModeChange, + onDisplayModeChange = { presenter.displayMode = it }, navigateUp = navigateUp, onWebViewClick = onWebViewClick, onHelpClick = onHelpClick, @@ -86,31 +96,17 @@ fun BrowseSourceScreen( ) }, floatingActionButton = { - // SY --> - // if (presenter.filters.isNotEmpty()) { - ExtendedFloatingActionButton( - 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, + BrowseSourceFloatingActionButton( + isVisible = presenter.filters.isNotEmpty(), + onFabClick = onFabClick, ) - // } - // SY <-- }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { paddingValues -> BrowseSourceContent( - source = presenter.source, + state = presenter, mangaList = mangaList, getMangaState = { presenter.getManga(it) }, // SY --> @@ -130,18 +126,113 @@ fun BrowseSourceScreen( onLocalSourceHelpClick = onHelpClick, onMangaClick = onMangaClick, 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 fun BrowseSourceContent( - source: CatalogueSource?, + state: BrowseSourceState, mangaList: LazyPagingItems */Pair/* SY <-- */>, getMangaState: @Composable ((Manga) -> State), // SY --> getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State), // SY <-- + header: (@Composable () -> Unit)? = null, columns: GridCells, ehentaiBrowseDisplayMode: Boolean, displayMode: LibraryDisplayMode, @@ -186,7 +277,7 @@ fun BrowseSourceContent( if (mangaList.itemCount <= 0 && errorState != null && errorState is LoadState.Error) { EmptyScreen( message = getErrorMessage(errorState), - actions = if (source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) { + actions = if (state.source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) { listOf( EmptyView.Action(R.string.local_source_help_guide, R.drawable.ic_help_24dp) { onLocalSourceHelpClick() }, ) @@ -204,8 +295,13 @@ fun BrowseSourceContent( return } + if (mangaList.itemCount == 0 && mangaList.loadState.refresh is LoadState.Loading) { + LoadingScreen() + return + } + // SY --> - if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) { + if (state.source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) { BrowseSourceEHentaiList( mangaList = mangaList, getMangaState = getMangaState, @@ -213,6 +309,7 @@ fun BrowseSourceContent( contentPadding = contentPadding, onMangaClick = onMangaClick, onMangaLongClick = onMangaLongClick, + header = header, ) return } @@ -230,6 +327,7 @@ fun BrowseSourceContent( contentPadding = contentPadding, onMangaClick = onMangaClick, onMangaLongClick = onMangaLongClick, + header = header, ) } LibraryDisplayMode.List -> { @@ -242,6 +340,7 @@ fun BrowseSourceContent( contentPadding = contentPadding, onMangaClick = onMangaClick, onMangaLongClick = onMangaLongClick, + header = header, ) } else -> { @@ -255,6 +354,7 @@ fun BrowseSourceContent( contentPadding = contentPadding, onMangaClick = onMangaClick, onMangaLongClick = onMangaLongClick, + header = header, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceState.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceState.kt index 45a9fa4ce..2e71236bf 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceState.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceState.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.domain.source.interactor.GetRemoteManga import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter @@ -16,22 +17,31 @@ interface BrowseSourceState { val source: CatalogueSource? var searchQuery: String? val currentQuery: String + val isUserQuery: Boolean val filters: FilterList val filterItems: List> - val appliedFilters: FilterList + val currentFilters: FilterList var dialog: BrowseSourcePresenter.Dialog? } 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 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 val filterItems: List> by derivedStateOf { filters.toItems() } - override var appliedFilters by mutableStateOf(FilterList()) + override var currentFilters by mutableStateOf(FilterList()) override var dialog: BrowseSourcePresenter.Dialog? by mutableStateOf(null) } diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt index 33016b564..6c6c22565 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt @@ -1,38 +1,81 @@ package eu.kanade.presentation.browse +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState 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.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.webview.WebViewActivity +import eu.kanade.tachiyomi.ui.more.MoreController @Composable fun SourceSearchScreen( presenter: BrowseSourcePresenter, navigateUp: () -> Unit, onFabClick: () -> Unit, - onClickManga: (Manga) -> Unit, - // SY --> - onSettingsClick: () -> Unit, - // SY <-- + onMangaClick: (Manga) -> Unit, + onWebViewClick: () -> Unit, ) { - val context = LocalContext.current + val columns by presenter.getColumnsPreferenceForCurrentOrientation() - BrowseSourceScreen( - presenter = presenter, - navigateUp = navigateUp, - onDisplayModeChange = { presenter.displayMode = (it) }, - onFabClick = onFabClick, - onMangaClick = onClickManga, - onMangaLongClick = onClickManga, - onWebViewClick = f@{ - val source = presenter.source as? HttpSource ?: return@f - val intent = WebViewActivity.newIntent(context, source.baseUrl, source.id, source.name) - context.startActivity(intent) + val mangaList = presenter.getMangaList().collectAsLazyPagingItems() + + val snackbarHostState = remember { SnackbarHostState() } + + val uriHandler = LocalUriHandler.current + + val onHelpClick = { + uriHandler.openUri(LocalSource.HELP_URL) + } + + Scaffold( + topBar = { scrollBehavior -> + BrowseSourceSearchToolbar( + searchQuery = presenter.searchQuery ?: "", + onSearchQueryChanged = { presenter.searchQuery = it }, + navigateUp = navigateUp, + onResetClick = { presenter.searchQuery = "" }, + onSearchClick = { presenter.search() }, + scrollBehavior = scrollBehavior, + ) }, - // SY --> - onSettingsClick = onSettingsClick, - // SY <-- - ) + floatingActionButton = { + BrowseSourceFloatingActionButton( + 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, + ) + } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt index 04b053ddf..4e772e4c5 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource 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.Source import eu.kanade.presentation.browse.components.BaseSourceItem @@ -50,9 +51,8 @@ import kotlinx.coroutines.flow.collectLatest @Composable fun SourcesScreen( presenter: SourcesPresenter, - onClickItem: (Source) -> Unit, + onClickItem: (Source, String) -> Unit, onClickDisable: (Source) -> Unit, - onClickLatest: (Source) -> Unit, onClickPin: (Source) -> Unit, onClickSetCategories: (Source, List) -> Unit, onClickToggleDataSaver: (Source) -> Unit, @@ -66,7 +66,6 @@ fun SourcesScreen( state = presenter, onClickItem = onClickItem, onClickDisable = onClickDisable, - onClickLatest = onClickLatest, onClickPin = onClickPin, onClickSetCategories = onClickSetCategories, onClickToggleDataSaver = onClickToggleDataSaver, @@ -87,9 +86,8 @@ fun SourcesScreen( @Composable fun SourceList( state: SourcesState, - onClickItem: (Source) -> Unit, + onClickItem: (Source, String) -> Unit, onClickDisable: (Source) -> Unit, - onClickLatest: (Source) -> Unit, onClickPin: (Source) -> Unit, onClickSetCategories: (Source, List) -> Unit, onClickToggleDataSaver: (Source) -> Unit, @@ -127,7 +125,6 @@ fun SourceList( showPin = state.showPin, onClickItem = onClickItem, onLongClickItem = { state.dialog = Dialog.SourceLongClick(it) }, - onClickLatest = onClickLatest, onClickPin = onClickPin, ) } @@ -199,19 +196,18 @@ fun SourceItem( showLatest: Boolean, showPin: Boolean, // SY <-- - onClickItem: (Source) -> Unit, + onClickItem: (Source, String) -> Unit, onLongClickItem: (Source) -> Unit, - onClickLatest: (Source) -> Unit, onClickPin: (Source) -> Unit, ) { BaseSourceItem( modifier = modifier, source = source, - onClickItem = { onClickItem(source) }, + onClickItem = { onClickItem(source, GetRemoteManga.QUERY_POPULAR) }, onLongClickItem = { onLongClickItem(source) }, action = { source -> if (source.supportsLatest /* SY --> */ && showLatest /* SY <-- */) { - TextButton(onClick = { onClickLatest(source) }) { + TextButton(onClick = { onClickItem(source, GetRemoteManga.QUERY_LATEST) }) { Text( text = stringResource(R.string.latest), style = LocalTextStyle.current.copy( diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseLatestToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseLatestToolbar.kt deleted file mode 100644 index ff72bcd3c..000000000 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseLatestToolbar.kt +++ /dev/null @@ -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() }, - // 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, - ) -} diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt index 004c4bfb5..eac62096d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt @@ -37,6 +37,7 @@ fun BrowseSourceComfortableGrid( // SY --> getMetadataState: @Composable ((Manga, RaisedSearchMetadata?) -> State), // SY <-- + header: (@Composable () -> Unit)? = null, columns: GridCells, contentPadding: PaddingValues, onMangaClick: (Manga) -> Unit, @@ -44,12 +45,18 @@ fun BrowseSourceComfortableGrid( ) { LazyVerticalGrid( columns = columns, - contentPadding = PaddingValues(8.dp) + contentPadding, + contentPadding = PaddingValues(8.dp, 4.dp) + contentPadding, horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { - item(span = { GridItemSpan(maxLineSpan) }) { - if (mangaList.loadState.prepend is LoadState.Loading) { + if (header != null) { + item(span = { GridItemSpan(maxLineSpan) }) { + header() + } + } + + if (mangaList.loadState.prepend is LoadState.Loading) { + item(span = { GridItemSpan(maxLineSpan) }) { 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() } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt index 9bf37e215..8cf18c49c 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt @@ -48,13 +48,20 @@ fun BrowseSourceCompactGrid( contentPadding: PaddingValues, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, + header: (@Composable () -> Unit)? = null, ) { LazyVerticalGrid( columns = columns, - contentPadding = PaddingValues(8.dp) + contentPadding, + contentPadding = PaddingValues(8.dp, 4.dp) + contentPadding, horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { + if (header != null) { + item(span = { GridItemSpan(maxLineSpan) }) { + header() + } + } + item(span = { GridItemSpan(maxLineSpan) }) { if (mangaList.loadState.prepend is LoadState.Loading) { BrowseSourceLoadingItem() diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceEHentaiList.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceEHentaiList.kt index 11a8d9603..669bb922c 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceEHentaiList.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceEHentaiList.kt @@ -58,10 +58,17 @@ fun BrowseSourceEHentaiList( contentPadding: PaddingValues, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, + header: (@Composable () -> Unit)? = null, ) { LazyColumn( contentPadding = contentPadding, ) { + if (header != null) { + item { + header() + } + } + item { if (mangaList.loadState.prepend is LoadState.Loading) { BrowseSourceLoadingItem() diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt index 599ecce5b..9ab08c13b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt @@ -36,10 +36,17 @@ fun BrowseSourceList( contentPadding: PaddingValues, onMangaClick: (Manga) -> Unit, onMangaLongClick: (Manga) -> Unit, + header: (@Composable () -> Unit)? = null, ) { LazyColumn( contentPadding = contentPadding, ) { + if (header != null) { + item { + header() + } + } + item { if (mangaList.loadState.prepend is LoadState.Loading) { BrowseSourceLoadingItem() diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceLoadingItem.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceLoadingItem.kt index d27fadf4d..2ecf8539b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceLoadingItem.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceLoadingItem.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -18,8 +17,6 @@ fun BrowseSourceLoadingItem() { .padding(vertical = 16.dp), horizontalArrangement = Arrangement.Center, ) { - CircularProgressIndicator( - modifier = Modifier.size(64.dp), - ) + CircularProgressIndicator() } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt index a83113599..b5eabfdc7 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt @@ -49,11 +49,15 @@ fun BrowseSourceToolbar( ) { if (state.searchQuery == null) { BrowseSourceRegularToolbar( - source = source, + title = if (state.isUserQuery) state.currentQuery else source.name, + isLocalSource = source is LocalSource, + // SY --> + isConfigurableSource = source.anyIs(), + // SY <-- displayMode = displayMode, onDisplayModeChange = onDisplayModeChange, navigateUp = navigateUp, - onSearchClick = { state.searchQuery = "" }, + onSearchClick = { state.searchQuery = if (state.isUserQuery) state.currentQuery else "" }, onWebViewClick = onWebViewClick, onHelpClick = onHelpClick, // SY --> @@ -65,10 +69,7 @@ fun BrowseSourceToolbar( BrowseSourceSearchToolbar( searchQuery = state.searchQuery!!, onSearchQueryChanged = { state.searchQuery = it }, - navigateUp = { - state.searchQuery = null - onSearch() - }, + navigateUp = { state.searchQuery = null }, onResetClick = { state.searchQuery = "" }, onSearchClick = onSearch, scrollBehavior = scrollBehavior, @@ -78,7 +79,9 @@ fun BrowseSourceToolbar( @Composable fun BrowseSourceRegularToolbar( - source: CatalogueSource, + title: String, + isLocalSource: Boolean, + isConfigurableSource: Boolean, displayMode: LibraryDisplayMode?, onDisplayModeChange: (LibraryDisplayMode) -> Unit, navigateUp: () -> Unit, @@ -92,7 +95,7 @@ fun BrowseSourceRegularToolbar( ) { AppBar( navigateUp = navigateUp, - title = source.name, + title = title, actions = { var selectingDisplayMode by remember { mutableStateOf(false) } AppBarActions( @@ -109,7 +112,7 @@ fun BrowseSourceRegularToolbar( onClick = { selectingDisplayMode = true }, ).takeIf { displayMode != null }, // SY <-- - if (source is LocalSource) { + if (isLocalSource) { AppBar.Action( title = stringResource(id = R.string.label_help), icon = Icons.Outlined.Help, @@ -123,11 +126,13 @@ fun BrowseSourceRegularToolbar( ) }, // SY --> - AppBar.Action( - title = stringResource(R.string.action_settings), - icon = Icons.Outlined.Settings, - onClick = onSettingsClick, - ).takeIf { source.anyIs() }, + if (isConfigurableSource) { + AppBar.Action( + title = stringResource(R.string.action_settings), + icon = Icons.Outlined.Settings, + onClick = onSettingsClick, + ) + } else null, // SY <-- ), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt index 42b6bc74b..77f339b9d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt @@ -3,4 +3,12 @@ package eu.kanade.tachiyomi.source.model data class FilterList(val list: List>) : List> by list { 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() + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt index 6518ca4c7..90a3fe630 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt @@ -5,13 +5,13 @@ import androidx.compose.material.icons.outlined.Add import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource import com.bluelinelabs.conductor.Router +import eu.kanade.domain.source.interactor.GetRemoteManga import eu.kanade.presentation.browse.FeedScreen import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.TabContent import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.base.controller.pushController 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 @Composable @@ -44,7 +44,7 @@ fun feedTab( }, onClickSource = { source -> presenter.preferences.lastUsedSource().set(source.id) - router?.pushController(LatestUpdatesController(source)) + router?.pushController(BrowseSourceController(source, GetRemoteManga.QUERY_LATEST)) }, onClickDelete = { presenter.dialog = FeedPresenter.Dialog.DeleteFeed(it) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt index 9ad0d7091..122cbb0ff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt @@ -8,10 +8,10 @@ import eu.kanade.domain.manga.model.Manga import eu.kanade.presentation.browse.SourceSearchScreen import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.ui.base.controller.pushController -import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesController +import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController 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.api.get @@ -31,12 +31,16 @@ class SourceSearchController( @Composable 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( presenter = presenter, navigateUp = { router.popCurrentController() }, onFabClick = { filterSheet?.show() }, // SY --> - onClickManga = { manga -> + onMangaClick = { manga -> val migrationListController = targetController as? MigrationListController ?: return@SourceSearchScreen val sourceManager = Injekt.get() val source = sourceManager.get(manga.source) ?: return@SourceSearchScreen @@ -44,10 +48,12 @@ class SourceSearchController( router.popCurrentController() router.popCurrentController() }, - onSettingsClick = { - router.pushController(SourcePreferencesController(presenter.source!!.id)) - }, // 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) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt index b0ae4101b..3946f0998 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt @@ -6,6 +6,7 @@ import androidx.compose.material.icons.outlined.TravelExplore import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource 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.components.AppBar 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.feed.SourceFeedController import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController -import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController import exh.ui.smartsearch.SmartSearchController @Composable @@ -45,13 +45,13 @@ fun sourcesTab( content = { SourcesScreen( presenter = presenter, - onClickItem = { source -> + onClickItem = { source, query -> // SY --> val controller = when { presenter.controllerMode == SourcesController.Mode.SMART_SEARCH -> SmartSearchController(source.id, presenter.smartSearchConfig!!) - presenter.useNewSourceNavigation -> SourceFeedController(source.id) - else -> BrowseSourceController(source) + (query.isBlank() || query == QUERY_POPULAR) && presenter.useNewSourceNavigation -> SourceFeedController(source.id) + else -> BrowseSourceController(source, query) } presenter.onOpenSource(source) router?.pushController(controller) @@ -60,10 +60,6 @@ fun sourcesTab( onClickDisable = { source -> presenter.toggleSource(source) }, - onClickLatest = { source -> - presenter.onOpenSource(source) - router?.pushController(LatestUpdatesController(source)) - }, onClickPin = { source -> presenter.togglePin(source) }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt index 2d9783e90..bd31d53d9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt @@ -102,6 +102,17 @@ open class BrowseSourceController(bundle: Bundle) : */ 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 override fun ComposeContent() { val scope = rememberCoroutineScope() @@ -110,7 +121,6 @@ open class BrowseSourceController(bundle: Bundle) : BrowseSourceScreen( presenter = presenter, navigateUp = { router.popCurrentController() }, - onDisplayModeChange = { presenter.displayMode = (it) }, onFabClick = { filterSheet?.show() }, onMangaClick = { router.pushController(MangaController(it.id, true)) }, 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) { filterSheet?.setSavedSearches(savedSearches) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index 77981eca6..eb67889e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.unit.dp import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import androidx.paging.PagingSource import androidx.paging.cachedIn import androidx.paging.map 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.source.interactor.DeleteSavedSearchById 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.model.SourcePagingSourceType import eu.kanade.domain.track.interactor.InsertTrack import eu.kanade.domain.track.model.toDomainTrack 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.savedsearches.models.SavedSearch import exh.source.getMainSource -import exh.source.isEhBasedSource import exh.util.nullIfBlank import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.Flow @@ -112,6 +112,7 @@ open class BrowseSourcePresenter( private val sourceManager: SourceManager = Injekt.get(), private val preferences: PreferencesHelper = Injekt.get(), private val coverCache: CoverCache = Injekt.get(), + private val getRemoteManga: GetRemoteManga = Injekt.get(), private val getManga: GetManga = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), @@ -130,6 +131,8 @@ open class BrowseSourcePresenter( // SY <-- ) : BasePresenter(), BrowseSourceState by state { + private val loggedServices by lazy { Injekt.get().services.filter { it.isLogged } } + var displayMode by preferences.sourceDisplayMode().asState() val ehentaiBrowseDisplayMode by preferences.enhancedEHentaiView().asState() @@ -148,11 +151,11 @@ open class BrowseSourcePresenter( @Composable fun getMangaList(): Flow */Pair/* SY <-- */>> { - return remember(currentQuery, appliedFilters) { + return remember(currentQuery, currentFilters) { Pager( PagingConfig(pageSize = 25), ) { - createPager(currentQuery, appliedFilters) + createSourcePagingSource(currentQuery, currentFilters) }.flow .map { it.map { @@ -169,12 +172,12 @@ open class BrowseSourcePresenter( @Composable fun getManga(initialManga: DomainManga): State { - return produceState(initialValue = initialManga, initialManga.url, initialManga.source) { + return produceState(initialValue = initialManga) { getManga.subscribe(initialManga.url, initialManga.source) .collectLatest { manga -> if (manga == null) return@collectLatest - launchIO { - initializeMangas(manga) + withIOContext { + initializeManga(manga) } value = manga } @@ -198,17 +201,15 @@ open class BrowseSourcePresenter( } fun resetFilter() { - state.appliedFilters = FilterList() val newFilters = source!!.getFilterList() state.filters = newFilters + state.currentFilters = state.filters } - fun search() { - state.currentQuery = searchQuery ?: "" + fun search(query: String? = null) { + state.currentQuery = query ?: searchQuery ?: "" } - private val loggedServices by lazy { Injekt.get().services.filter { it.isLogged } } - // SY --> private val filterSerializer = FilterSerializer() // SY <-- @@ -246,15 +247,6 @@ open class BrowseSourcePresenter( } .launchIn(presenterScope) // 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. * - * @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 withContext(NonCancellable) { val db = manga.toDbManga() @@ -394,18 +386,14 @@ open class BrowseSourcePresenter( * @param filters a list of active filters. */ fun setSourceFilter(filters: FilterList) { - state.appliedFilters = filters + state.currentFilters = filters } - open fun createPager(query: String, filters: FilterList): PagingSource> { - // SY --> - return if (source!!.isEhBasedSource()) { - EHentaiBrowsePagingSource(source!!, query, filters) - } else { - SourceBrowsePagingSource(source!!, query, filters) - } - // SY <-- + // SY --> + open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { + return getRemoteManga.subscribe(sourceId, currentQuery, currentFilters) } + // SY <-- /** * Get user categories. @@ -423,12 +411,6 @@ open class BrowseSourcePresenter( 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) { moveMangaToCategories(manga, categories.filter { it.id != 0L }.map { it.id }) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/NoResultsException.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/NoResultsException.kt deleted file mode 100644 index cf52294e7..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/NoResultsException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package eu.kanade.tachiyomi.ui.browse.source.browse - -class NoResultsException : Exception() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceBrowsePagingSource.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceBrowsePagingSource.kt deleted file mode 100644 index 5bb308724..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceBrowsePagingSource.kt +++ /dev/null @@ -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() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt index dbdad8768..ae1f1a77a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt @@ -8,6 +8,7 @@ import androidx.core.view.isVisible import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.source.interactor.GetRemoteManga import eu.kanade.presentation.browse.SourceFeedScreen import eu.kanade.tachiyomi.R 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.browse.source.browse.BrowseSourceController 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.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.withUIContext @@ -223,11 +223,11 @@ open class SourceFeedController : } private fun onLatestClick() { - router.replaceTopController(LatestUpdatesController(presenter.source).withFadeTransaction()) + router.replaceTopController(BrowseSourceController(presenter.source, GetRemoteManga.QUERY_LATEST).withFadeTransaction()) } private fun onBrowseClick() { - router.replaceTopController(BrowseSourceController(presenter.source).withFadeTransaction()) + router.replaceTopController(BrowseSourceController(presenter.source, GetRemoteManga.QUERY_POPULAR).withFadeTransaction()) } private fun onSavedSearchClick(savedSearch: SavedSearch) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesBrowsePagingSource.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesBrowsePagingSource.kt deleted file mode 100644 index 166a4a184..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesBrowsePagingSource.kt +++ /dev/null @@ -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() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesController.kt deleted file mode 100644 index e43e08a14..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesController.kt +++ /dev/null @@ -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 - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesPresenter.kt deleted file mode 100644 index d2a9030e8..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/latest/LatestUpdatesPresenter.kt +++ /dev/null @@ -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 */ Pair /*SY <-- */> { - return LatestUpdatesBrowsePagingSource(source!!) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 6c77f2826..443db5845 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -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.feed.SourceFeedController 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.library.LibraryController import eu.kanade.tachiyomi.ui.main.MainActivity @@ -483,10 +482,6 @@ class MangaController : FullComposeController { val controller = router.getControllerWithTag(R.id.nav_library.toString()) as LibraryController controller.search(query) } - is LatestUpdatesController -> { - // Search doesn't currently work in source Latest view - return - } is BrowseSourceController -> { router.handleBack() previousController.searchWithQuery(query) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index 8e0064788..ba48e4d4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -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.setting.database.ClearDatabaseController 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.withUIContext import eu.kanade.tachiyomi.util.preference.bindTo diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt index fd4c258c0..7639c39a4 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt @@ -1,15 +1,15 @@ package exh.md.follows +import eu.kanade.data.source.SourcePagingSource import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.online.all.MangaDex -import eu.kanade.tachiyomi.ui.browse.source.browse.BrowsePagingSource /** * 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 { - return source.fetchFollows(currentPage) + return mangadex.fetchFollows(currentPage) } } diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsPresenter.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsPresenter.kt index 14f6c488d..7e64d539e 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsPresenter.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsPresenter.kt @@ -4,10 +4,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.paging.PagingSource 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.SManga import eu.kanade.tachiyomi.source.online.all.MangaDex import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter import exh.metadata.metadata.base.RaisedSearchMetadata @@ -18,7 +17,7 @@ import exh.source.getMainSource */ class MangaDexFollowsPresenter(sourceId: Long) : BrowseSourcePresenter(sourceId) { - override fun createPager(query: String, filters: FilterList): PagingSource> { + override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { return MangaDexFollowsPagingSource(source!!.getMainSource() as MangaDex) } diff --git a/app/src/main/java/exh/md/similar/MangaDexSimilarPagingSource.kt b/app/src/main/java/exh/md/similar/MangaDexSimilarPagingSource.kt index af0c64e24..0cd379b97 100644 --- a/app/src/main/java/exh/md/similar/MangaDexSimilarPagingSource.kt +++ b/app/src/main/java/exh/md/similar/MangaDexSimilarPagingSource.kt @@ -1,23 +1,23 @@ 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.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage 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.coroutineScope /** * 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 { val mangasPage = coroutineScope { - val similarPageDef = async { source.getMangaSimilar(manga.toSManga()) } - val relatedPageDef = async { source.getMangaRelated(manga.toSManga()) } + val similarPageDef = async { mangadex.getMangaSimilar(manga.toSManga()) } + val relatedPageDef = async { mangadex.getMangaRelated(manga.toSManga()) } val similarPage = similarPageDef.await() val relatedPage = relatedPageDef.await() diff --git a/app/src/main/java/exh/md/similar/MangaDexSimilarPresenter.kt b/app/src/main/java/exh/md/similar/MangaDexSimilarPresenter.kt index a88a96382..25bee7ed8 100644 --- a/app/src/main/java/exh/md/similar/MangaDexSimilarPresenter.kt +++ b/app/src/main/java/exh/md/similar/MangaDexSimilarPresenter.kt @@ -5,11 +5,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.paging.PagingSource import eu.kanade.domain.manga.interactor.GetManga 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.SManga import eu.kanade.tachiyomi.source.online.all.MangaDex import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter import exh.metadata.metadata.base.RaisedSearchMetadata @@ -34,7 +33,7 @@ class MangaDexSimilarPresenter( this.manga = runBlocking { getManga.await(mangaId) } } - override fun createPager(query: String, filters: FilterList): PagingSource> { + override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { return MangaDexSimilarPagingSource(manga!!, source!!.getMainSource() as MangaDex) } diff --git a/app/src/main/java/exh/recs/RecommendsPagingSource.kt b/app/src/main/java/exh/recs/RecommendsPagingSource.kt index 2db0bd2d4..62d32bc7e 100644 --- a/app/src/main/java/exh/recs/RecommendsPagingSource.kt +++ b/app/src/main/java/exh/recs/RecommendsPagingSource.kt @@ -1,15 +1,16 @@ 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.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await 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.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.system.logcat import exh.util.MangaType @@ -193,10 +194,11 @@ class Anilist : API("https://graphql.anilist.co/") { } open class RecommendsPagingSource( + source: CatalogueSource, private val manga: Manga, private val smart: Boolean = true, private var preferredApi: API = API.MYANIMELIST, -) : BrowsePagingSource() { +) : SourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { if (smart) preferredApi = if (manga.mangaType() != MangaType.TYPE_MANGA) API.ANILIST else preferredApi diff --git a/app/src/main/java/exh/recs/RecommendsPresenter.kt b/app/src/main/java/exh/recs/RecommendsPresenter.kt index efbc1338a..9039637b7 100644 --- a/app/src/main/java/exh/recs/RecommendsPresenter.kt +++ b/app/src/main/java/exh/recs/RecommendsPresenter.kt @@ -1,13 +1,11 @@ package exh.recs import android.os.Bundle -import androidx.paging.PagingSource import eu.kanade.domain.manga.interactor.GetManga 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.SManga import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter -import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.coroutines.runBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -28,7 +26,7 @@ class RecommendsPresenter( this.manga = runBlocking { getManga.await(mangaId) } } - override fun createPager(query: String, filters: FilterList): PagingSource> { - return RecommendsPagingSource(manga!!) + override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { + return RecommendsPagingSource(source!!, manga!!) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51348d6fe..a0f0e1c41 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -582,6 +582,7 @@ Global search… Search for \"%1$s\" globally Latest + Popular Browse Local source guide You have no pinned sources