|
|
@ -1,45 +1,21 @@
|
|
|
|
package eu.kanade.presentation.browse
|
|
|
|
package eu.kanade.presentation.browse
|
|
|
|
|
|
|
|
|
|
|
|
import androidx.compose.foundation.background
|
|
|
|
|
|
|
|
import androidx.compose.foundation.horizontalScroll
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.PaddingValues
|
|
|
|
import androidx.compose.foundation.layout.PaddingValues
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.padding
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.size
|
|
|
|
|
|
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
|
|
import androidx.compose.foundation.rememberScrollState
|
|
|
|
|
|
|
|
import androidx.compose.material.icons.Icons
|
|
|
|
|
|
|
|
import androidx.compose.material.icons.outlined.DoneAll
|
|
|
|
|
|
|
|
import androidx.compose.material.icons.outlined.FilterList
|
|
|
|
|
|
|
|
import androidx.compose.material.icons.outlined.PushPin
|
|
|
|
|
|
|
|
import androidx.compose.material3.FilterChip
|
|
|
|
|
|
|
|
import androidx.compose.material3.FilterChipDefaults
|
|
|
|
|
|
|
|
import androidx.compose.material3.Icon
|
|
|
|
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.State
|
|
|
|
import androidx.compose.runtime.State
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
|
|
|
|
import androidx.compose.ui.res.stringResource
|
|
|
|
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchEmptyResultItem
|
|
|
|
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
|
|
|
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
|
|
|
import eu.kanade.tachiyomi.R
|
|
|
|
|
|
|
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
|
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreenModel
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreenModel
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
|
|
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
|
|
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
|
|
|
import tachiyomi.domain.manga.model.Manga
|
|
|
|
import tachiyomi.domain.manga.model.Manga
|
|
|
|
import tachiyomi.presentation.core.components.material.Divider
|
|
|
|
|
|
|
|
import tachiyomi.presentation.core.components.material.Scaffold
|
|
|
|
import tachiyomi.presentation.core.components.material.Scaffold
|
|
|
|
import tachiyomi.presentation.core.components.material.VerticalDivider
|
|
|
|
|
|
|
|
import tachiyomi.presentation.core.components.material.padding
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
@Composable
|
|
|
|
fun GlobalSearchScreen(
|
|
|
|
fun GlobalSearchScreen(
|
|
|
@ -56,7 +32,6 @@ fun GlobalSearchScreen(
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
Scaffold(
|
|
|
|
Scaffold(
|
|
|
|
topBar = { scrollBehavior ->
|
|
|
|
topBar = { scrollBehavior ->
|
|
|
|
Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
|
|
|
|
|
|
|
|
GlobalSearchToolbar(
|
|
|
|
GlobalSearchToolbar(
|
|
|
|
searchQuery = state.searchQuery,
|
|
|
|
searchQuery = state.searchQuery,
|
|
|
|
progress = state.progress,
|
|
|
|
progress = state.progress,
|
|
|
@ -64,68 +39,12 @@ fun GlobalSearchScreen(
|
|
|
|
navigateUp = navigateUp,
|
|
|
|
navigateUp = navigateUp,
|
|
|
|
onChangeSearchQuery = onChangeSearchQuery,
|
|
|
|
onChangeSearchQuery = onChangeSearchQuery,
|
|
|
|
onSearch = onSearch,
|
|
|
|
onSearch = onSearch,
|
|
|
|
|
|
|
|
sourceFilter = state.sourceFilter,
|
|
|
|
|
|
|
|
onChangeSearchFilter = onChangeSearchFilter,
|
|
|
|
|
|
|
|
onlyShowHasResults = state.onlyShowHasResults,
|
|
|
|
|
|
|
|
onToggleResults = onToggleResults,
|
|
|
|
scrollBehavior = scrollBehavior,
|
|
|
|
scrollBehavior = scrollBehavior,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.horizontalScroll(rememberScrollState())
|
|
|
|
|
|
|
|
.padding(horizontal = MaterialTheme.padding.small),
|
|
|
|
|
|
|
|
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// TODO: make this UX better; it only applies when triggering a new search
|
|
|
|
|
|
|
|
FilterChip(
|
|
|
|
|
|
|
|
selected = state.sourceFilter == SourceFilter.PinnedOnly,
|
|
|
|
|
|
|
|
onClick = { onChangeSearchFilter(SourceFilter.PinnedOnly) },
|
|
|
|
|
|
|
|
leadingIcon = {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.PushPin,
|
|
|
|
|
|
|
|
contentDescription = null,
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.size(FilterChipDefaults.IconSize),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
label = {
|
|
|
|
|
|
|
|
Text(text = stringResource(id = R.string.pinned_sources))
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
FilterChip(
|
|
|
|
|
|
|
|
selected = state.sourceFilter == SourceFilter.All,
|
|
|
|
|
|
|
|
onClick = { onChangeSearchFilter(SourceFilter.All) },
|
|
|
|
|
|
|
|
leadingIcon = {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.DoneAll,
|
|
|
|
|
|
|
|
contentDescription = null,
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.size(FilterChipDefaults.IconSize),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
label = {
|
|
|
|
|
|
|
|
Text(text = stringResource(id = R.string.all))
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VerticalDivider()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FilterChip(
|
|
|
|
|
|
|
|
selected = state.onlyShowHasResults,
|
|
|
|
|
|
|
|
onClick = { onToggleResults() },
|
|
|
|
|
|
|
|
leadingIcon = {
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
imageVector = Icons.Outlined.FilterList,
|
|
|
|
|
|
|
|
contentDescription = null,
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.size(FilterChipDefaults.IconSize),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
label = {
|
|
|
|
|
|
|
|
Text(text = stringResource(id = R.string.has_results))
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Divider()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
) { paddingValues ->
|
|
|
|
) { paddingValues ->
|
|
|
|
GlobalSearchContent(
|
|
|
|
GlobalSearchContent(
|
|
|
@ -141,7 +60,7 @@ fun GlobalSearchScreen(
|
|
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
@Composable
|
|
|
|
internal fun GlobalSearchContent(
|
|
|
|
internal fun GlobalSearchContent(
|
|
|
|
sourceId: Long? = null,
|
|
|
|
fromSourceId: Long? = null,
|
|
|
|
items: Map<CatalogueSource, SearchItemResult>,
|
|
|
|
items: Map<CatalogueSource, SearchItemResult>,
|
|
|
|
contentPadding: PaddingValues,
|
|
|
|
contentPadding: PaddingValues,
|
|
|
|
getManga: @Composable (Manga) -> State<Manga>,
|
|
|
|
getManga: @Composable (Manga) -> State<Manga>,
|
|
|
@ -155,7 +74,7 @@ internal fun GlobalSearchContent(
|
|
|
|
items.forEach { (source, result) ->
|
|
|
|
items.forEach { (source, result) ->
|
|
|
|
item(key = source.id) {
|
|
|
|
item(key = source.id) {
|
|
|
|
GlobalSearchResultItem(
|
|
|
|
GlobalSearchResultItem(
|
|
|
|
title = sourceId?.let { "▶ ${source.name}".takeIf { source.id == sourceId } } ?: source.name,
|
|
|
|
title = fromSourceId?.let { "▶ ${source.name}".takeIf { source.id == fromSourceId } } ?: source.name,
|
|
|
|
subtitle = LocaleHelper.getDisplayName(source.lang),
|
|
|
|
subtitle = LocaleHelper.getDisplayName(source.lang),
|
|
|
|
onClick = { onClickSource(source) },
|
|
|
|
onClick = { onClickSource(source) },
|
|
|
|
) {
|
|
|
|
) {
|
|
|
@ -164,11 +83,6 @@ internal fun GlobalSearchContent(
|
|
|
|
GlobalSearchLoadingResultItem()
|
|
|
|
GlobalSearchLoadingResultItem()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is SearchItemResult.Success -> {
|
|
|
|
is SearchItemResult.Success -> {
|
|
|
|
if (result.isEmpty) {
|
|
|
|
|
|
|
|
GlobalSearchEmptyResultItem()
|
|
|
|
|
|
|
|
return@GlobalSearchResultItem
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GlobalSearchCardRow(
|
|
|
|
GlobalSearchCardRow(
|
|
|
|
titles = result.result,
|
|
|
|
titles = result.result,
|
|
|
|
getManga = getManga,
|
|
|
|
getManga = getManga,
|
|
|
|