Pass listing query to BrowseSourceScreen (#8763)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
This commit is contained in:
stevenyomi 2022-12-17 23:19:43 -05:00 committed by Jobobby04
parent a6d0031462
commit f02d41051e
10 changed files with 71 additions and 63 deletions

View File

@ -28,7 +28,6 @@ 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
@ -42,13 +41,14 @@ import eu.kanade.presentation.util.topSmallPaddingValues
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.browse.source.SourcesState import eu.kanade.tachiyomi.ui.browse.source.SourcesState
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
@Composable @Composable
fun SourcesScreen( fun SourcesScreen(
state: SourcesState, state: SourcesState,
contentPadding: PaddingValues, contentPadding: PaddingValues,
onClickItem: (Source, String) -> Unit, onClickItem: (Source, Listing) -> Unit,
onClickPin: (Source) -> Unit, onClickPin: (Source) -> Unit,
onLongClickItem: (Source) -> Unit, onLongClickItem: (Source) -> Unit,
) { ) {
@ -136,18 +136,18 @@ private fun SourceItem(
showLatest: Boolean, showLatest: Boolean,
showPin: Boolean, showPin: Boolean,
// SY <-- // SY <--
onClickItem: (Source, String) -> Unit, onClickItem: (Source, Listing) -> Unit,
onLongClickItem: (Source) -> Unit, onLongClickItem: (Source) -> Unit,
onClickPin: (Source) -> Unit, onClickPin: (Source) -> Unit,
) { ) {
BaseSourceItem( BaseSourceItem(
modifier = modifier, modifier = modifier,
source = source, source = source,
onClickItem = { onClickItem(source, GetRemoteManga.QUERY_POPULAR) }, onClickItem = { onClickItem(source, Listing.Popular) },
onLongClickItem = { onLongClickItem(source) }, onLongClickItem = { onLongClickItem(source) },
action = { action = {
if (source.supportsLatest /* SY --> */ && showLatest /* SY <-- */) { if (source.supportsLatest /* SY --> */ && showLatest /* SY <-- */) {
TextButton(onClick = { onClickItem(source, GetRemoteManga.QUERY_LATEST) }) { TextButton(onClick = { onClickItem(source, Listing.Latest) }) {
Text( Text(
text = stringResource(R.string.latest), text = stringResource(R.string.latest),
style = LocalTextStyle.current.copy( style = LocalTextStyle.current.copy(

View File

@ -240,7 +240,8 @@ fun SearchToolbar(
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val searchAndClearFocus: () -> Unit = { val searchAndClearFocus: () -> Unit = f@{
if (searchQuery.isBlank()) return@f
onSearch(searchQuery) onSearch(searchQuery)
focusManager.clearFocus() focusManager.clearFocus()
keyboardController?.hide() keyboardController?.hide()

View File

@ -15,7 +15,6 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material.icons.filled.OpenInNew
import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material.icons.outlined.NewReleases
import androidx.compose.material3.Button
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults import androidx.compose.material3.NavigationBarDefaults
@ -68,7 +67,7 @@ fun NewUpdateScreen(
vertical = MaterialTheme.padding.small, vertical = MaterialTheme.padding.small,
), ),
) { ) {
Button( TextButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
onClick = onAcceptUpdate, onClick = onAcceptUpdate,
) { ) {

View File

@ -50,6 +50,7 @@ fun Screen.feedTab(): TabContent {
navigator.push( navigator.push(
BrowseSourceScreen( BrowseSourceScreen(
source.id, source.id,
listingQuery = null,
savedSearch = savedSearch.id, savedSearch = savedSearch.id,
), ),
) )

View File

@ -30,7 +30,7 @@ import eu.kanade.tachiyomi.util.Constants
data class SourceSearchScreen( data class SourceSearchScreen(
private val oldManga: Manga, private val oldManga: Manga,
private val sourceId: Long, private val sourceId: Long,
private val query: String? = null, private val query: String?,
) : Screen { ) : Screen {
@Composable @Composable
@ -39,7 +39,7 @@ data class SourceSearchScreen(
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId = sourceId, searchQuery = query) } val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId, query) }
val state by screenModel.state.collectAsState() val state by screenModel.state.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }

View File

@ -12,7 +12,6 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.domain.source.interactor.GetRemoteManga.Companion.QUERY_POPULAR
import eu.kanade.presentation.browse.SourceCategoriesDialog import eu.kanade.presentation.browse.SourceCategoriesDialog
import eu.kanade.presentation.browse.SourceOptionsDialog import eu.kanade.presentation.browse.SourceOptionsDialog
import eu.kanade.presentation.browse.SourcesScreen import eu.kanade.presentation.browse.SourcesScreen
@ -21,6 +20,7 @@ import eu.kanade.presentation.components.TabContent
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen.SmartSearchConfig import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen.SmartSearchConfig
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedScreen import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedScreen
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
import exh.ui.smartsearch.SmartSearchScreen import exh.ui.smartsearch.SmartSearchScreen
@ -62,12 +62,12 @@ fun Screen.sourcesTab(
SourcesScreen( SourcesScreen(
state = state, state = state,
contentPadding = contentPadding, contentPadding = contentPadding,
onClickItem = { source, query -> onClickItem = { source, listing ->
// SY --> // SY -->
val screen = when { val screen = when {
smartSearchConfig != null -> SmartSearchScreen(source.id, smartSearchConfig) smartSearchConfig != null -> SmartSearchScreen(source.id, smartSearchConfig)
(query.isBlank() || query == QUERY_POPULAR) && screenModel.useNewSourceNavigation -> SourceFeedScreen(source.id) listing == Listing.Popular && screenModel.useNewSourceNavigation -> SourceFeedScreen(source.id)
else -> BrowseSourceScreen(source.id, query) else -> BrowseSourceScreen(source.id, listing.query)
} }
screenModel.onOpenSource(source) screenModel.onOpenSource(source)
navigator.push(screen) navigator.push(screen)

View File

@ -39,7 +39,6 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.screen.uniqueScreenKey import cafe.adriel.voyager.core.screen.uniqueScreenKey
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.domain.source.interactor.GetRemoteManga
import eu.kanade.presentation.browse.BrowseSourceContent import eu.kanade.presentation.browse.BrowseSourceContent
import eu.kanade.presentation.browse.components.BrowseSourceToolbar import eu.kanade.presentation.browse.components.BrowseSourceToolbar
import eu.kanade.presentation.browse.components.FailedToLoadSavedSearchDialog import eu.kanade.presentation.browse.components.FailedToLoadSavedSearchDialog
@ -56,6 +55,7 @@ import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
import eu.kanade.tachiyomi.ui.category.CategoryScreen import eu.kanade.tachiyomi.ui.category.CategoryScreen
import eu.kanade.tachiyomi.ui.manga.MangaScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
@ -67,7 +67,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
data class BrowseSourceScreen( data class BrowseSourceScreen(
private val sourceId: Long, private val sourceId: Long,
private val query: String? = null, private val listingQuery: String?,
// SY --> // SY -->
private val filtersJson: String? = null, private val filtersJson: String? = null,
private val savedSearch: Long? = null, private val savedSearch: Long? = null,
@ -92,7 +92,7 @@ data class BrowseSourceScreen(
val screenModel = rememberScreenModel { val screenModel = rememberScreenModel {
BrowseSourceScreenModel( BrowseSourceScreenModel(
sourceId = sourceId, sourceId = sourceId,
searchQuery = query, listingQuery = listingQuery,
// SY --> // SY -->
filtersJson = filtersJson, filtersJson = filtersJson,
savedSearch = savedSearch, savedSearch = savedSearch,
@ -147,10 +147,10 @@ data class BrowseSourceScreen(
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
FilterChip( FilterChip(
selected = state.currentFilter == BrowseSourceScreenModel.Filter.Popular, selected = state.listing == Listing.Popular,
onClick = { onClick = {
screenModel.reset() screenModel.resetFilters()
screenModel.search(GetRemoteManga.QUERY_POPULAR) screenModel.setListing(Listing.Popular)
}, },
leadingIcon = { leadingIcon = {
Icon( Icon(
@ -166,10 +166,10 @@ data class BrowseSourceScreen(
) )
if (screenModel.source.supportsLatest) { if (screenModel.source.supportsLatest) {
FilterChip( FilterChip(
selected = state.currentFilter == BrowseSourceScreenModel.Filter.Latest, selected = state.listing == Listing.Latest,
onClick = { onClick = {
screenModel.reset() screenModel.resetFilters()
screenModel.search(GetRemoteManga.QUERY_LATEST) screenModel.setListing(Listing.Latest)
}, },
leadingIcon = { leadingIcon = {
Icon( Icon(
@ -186,7 +186,7 @@ data class BrowseSourceScreen(
} }
/* SY --> if (state.filters.isNotEmpty())*/ run /* SY <-- */ { /* SY --> if (state.filters.isNotEmpty())*/ run /* SY <-- */ {
FilterChip( FilterChip(
selected = state.currentFilter is BrowseSourceScreenModel.Filter.UserInput, selected = state.listing is Listing.Search,
onClick = screenModel::openFilterSheet, onClick = screenModel::openFilterSheet,
leadingIcon = { leadingIcon = {
Icon( Icon(

View File

@ -107,7 +107,7 @@ import eu.kanade.tachiyomi.source.model.Filter as SourceModelFilter
open class BrowseSourceScreenModel( open class BrowseSourceScreenModel(
private val sourceId: Long, private val sourceId: Long,
searchQuery: String?, listingQuery: String?,
// SY --> // SY -->
private val filtersJson: String? = null, private val filtersJson: String? = null,
private val savedSearch: Long? = null, private val savedSearch: Long? = null,
@ -135,7 +135,7 @@ open class BrowseSourceScreenModel(
private val insertSavedSearch: InsertSavedSearch = Injekt.get(), private val insertSavedSearch: InsertSavedSearch = Injekt.get(),
private val getExhSavedSearch: GetExhSavedSearch = Injekt.get(), private val getExhSavedSearch: GetExhSavedSearch = Injekt.get(),
// SY <-- // SY <--
) : StateScreenModel<BrowseSourceScreenModel.State>(State(Filter.valueOf(searchQuery))) { ) : StateScreenModel<BrowseSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } } private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
@ -149,16 +149,16 @@ open class BrowseSourceScreenModel(
private var filterSheet: SourceFilterSheet? = null private var filterSheet: SourceFilterSheet? = null
/** /**
* Flow of Pager flow tied to [State.currentFilter] * Flow of Pager flow tied to [State.listing]
*/ */
val mangaPagerFlowFlow = state.map { it.currentFilter } val mangaPagerFlowFlow = state.map { it.listing }
.distinctUntilChanged() .distinctUntilChanged()
.map { currentFilter -> .map { listing ->
Pager( Pager(
PagingConfig(pageSize = 25), PagingConfig(pageSize = 25),
) { ) {
// SY --> // SY -->
createSourcePagingSource(currentFilter.query ?: "", currentFilter.filters) createSourcePagingSource(listing.query ?: "", listing.filters)
// SY <-- // SY <--
}.flow }.flow
.map { pagingData -> .map { pagingData ->
@ -184,7 +184,19 @@ open class BrowseSourceScreenModel(
// SY <-- // SY <--
init { init {
mutableState.update { it.copy(filters = source.getFilterList()) } mutableState.update {
val initialListing = it.listing
val listing = if (initialListing is Listing.Search) {
initialListing.copy(filters = source.getFilterList())
} else {
initialListing
}
it.copy(
listing = listing,
filters = source.getFilterList(),
)
}
// SY --> // SY -->
val savedSearchFilters = savedSearch val savedSearchFilters = savedSearch
@ -234,31 +246,26 @@ open class BrowseSourceScreenModel(
} }
// SY <-- // SY <--
fun reset() { fun resetFilters() {
mutableState.update { it.copy(filters = source.getFilterList()) } mutableState.update { it.copy(filters = source.getFilterList()) }
} }
fun setListing(listing: Listing) {
mutableState.update { it.copy(listing = listing) }
}
fun search(query: String? = null, filters: FilterList? = null) { fun search(query: String? = null, filters: FilterList? = null) {
// SY --> // SY -->
if (filters != null && filters !== state.value.filters) { if (filters != null && filters !== state.value.filters) {
mutableState.update { state -> state.copy(filters = filters) } mutableState.update { state -> state.copy(filters = filters) }
} }
// SY <-- // SY <--
Filter.valueOf(query).let { val input = state.value.listing as? Listing.Search
if (it !is Filter.UserInput) { ?: Listing.Search(query = null, filters = source.getFilterList())
mutableState.update { state -> state.copy(currentFilter = it) }
return
}
}
val input = if (state.value.currentFilter is Filter.UserInput) {
state.value.currentFilter as Filter.UserInput
} else {
Filter.UserInput()
}
mutableState.update { mutableState.update {
it.copy( it.copy(
currentFilter = input.copy( listing = input.copy(
query = query ?: input.query, query = query ?: input.query,
filters = filters ?: input.filters, filters = filters ?: input.filters,
), ),
@ -297,14 +304,14 @@ open class BrowseSourceScreenModel(
} }
mutableState.update { mutableState.update {
val filter = if (genreExists) { val listing = if (genreExists) {
Filter.UserInput(filters = defaultFilters) Listing.Search(query = null, filters = defaultFilters)
} else { } else {
Filter.UserInput(query = genreName) Listing.Search(query = genreName, filters = defaultFilters)
} }
it.copy( it.copy(
filters = defaultFilters, filters = defaultFilters,
currentFilter = filter, listing = listing,
) )
} }
} }
@ -472,8 +479,8 @@ open class BrowseSourceScreenModel(
// SY <-- // SY <--
onFilterClicked = { search(filters = state.filters) }, onFilterClicked = { search(filters = state.filters) },
onResetClicked = { onResetClicked = {
reset() resetFilters()
filterSheet?.setFilters(state.value.filterItems) filterSheet?.setFilters(state.filterItems)
}, },
// EXH --> // EXH -->
onSaveClicked = { onSaveClicked = {
@ -511,20 +518,20 @@ open class BrowseSourceScreenModel(
// EXH <-- // EXH <--
) )
filterSheet?.setFilters(state.value.filterItems) filterSheet?.setFilters(state.filterItems)
} }
sealed class Filter(open val query: String?, open val filters: FilterList) { sealed class Listing(open val query: String?, open val filters: FilterList) {
object Popular : Filter(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList()) object Popular : Listing(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList())
object Latest : Filter(query = GetRemoteManga.QUERY_LATEST, filters = FilterList()) object Latest : Listing(query = GetRemoteManga.QUERY_LATEST, filters = FilterList())
data class UserInput(override val query: String? = null, override val filters: FilterList = FilterList()) : Filter(query = query, filters = filters) data class Search(override val query: String?, override val filters: FilterList) : Listing(query = query, filters = filters)
companion object { companion object {
fun valueOf(query: String?): Filter { fun valueOf(query: String?): Listing {
return when (query) { return when (query) {
GetRemoteManga.QUERY_POPULAR -> Popular GetRemoteManga.QUERY_POPULAR -> Popular
GetRemoteManga.QUERY_LATEST -> Latest GetRemoteManga.QUERY_LATEST -> Latest
else -> UserInput(query = query) else -> Search(query = query, filters = FilterList()) // filters are filled in later
} }
} }
} }
@ -548,7 +555,7 @@ open class BrowseSourceScreenModel(
@Immutable @Immutable
data class State( data class State(
val currentFilter: Filter, val listing: Listing,
val filters: FilterList = FilterList(), val filters: FilterList = FilterList(),
val toolbarQuery: String? = null, val toolbarQuery: String? = null,
val dialog: Dialog? = null, val dialog: Dialog? = null,
@ -557,7 +564,7 @@ open class BrowseSourceScreenModel(
// SY <-- // SY <--
) { ) {
val filterItems get() = filters.toItems() val filterItems get() = filters.toItems()
val isUserQuery get() = currentFilter is Filter.UserInput && !currentFilter.query.isNullOrEmpty() val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty()
} }
// EXH --> // EXH -->
@ -565,8 +572,8 @@ open class BrowseSourceScreenModel(
name: String, name: String,
) { ) {
coroutineScope.launchNonCancellable { coroutineScope.launchNonCancellable {
val query = state.value.currentFilter.query val query = state.value.listing.query
val filterList = state.value.currentFilter.filters.ifEmpty { source.getFilterList() } val filterList = state.value.listing.filters.ifEmpty { source.getFilterList() }
insertSavedSearch.await( insertSavedSearch.await(
SavedSearch( SavedSearch(
id = -1, id = -1,

View File

@ -199,7 +199,7 @@ class SourceFeedScreen(val sourceId: Long) : Screen {
} }
private fun onSavedSearchClick(navigator: Navigator, source: CatalogueSource, savedSearch: SavedSearch) { private fun onSavedSearchClick(navigator: Navigator, source: CatalogueSource, savedSearch: SavedSearch) {
navigator.replace(BrowseSourceScreen(source.id, savedSearch = savedSearch.id)) navigator.replace(BrowseSourceScreen(source.id, listingQuery = null, savedSearch = savedSearch.id))
} }
private fun onSearchClick(navigator: Navigator, source: CatalogueSource, query: String) { private fun onSearchClick(navigator: Navigator, source: CatalogueSource, query: String) {

View File

@ -52,7 +52,7 @@ class SmartSearchScreen(private val sourceId: Long, private val smartSearchConfi
navigator.push( navigator.push(
BrowseSourceScreen( BrowseSourceScreen(
sourceId = screenModel.source.id, sourceId = screenModel.source.id,
query = smartSearchConfig.origTitle, listingQuery = smartSearchConfig.origTitle,
smartSearchConfig = smartSearchConfig, smartSearchConfig = smartSearchConfig,
), ),
) )