diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index c81fa16329..582dd61d7b 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -30,7 +30,5 @@ class SourcePreferences( fun trustedSignatures() = preferenceStore.getStringSet("trusted_signatures", emptySet()) - fun searchPinnedSourcesOnly() = preferenceStore.getBoolean("search_pinned_sources_only", false) - fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false) } diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 886f9960a2..4a80724f0d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -30,23 +30,25 @@ import eu.kanade.presentation.browse.components.GlobalSearchResultItem import eu.kanade.presentation.browse.components.GlobalSearchToolbar import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.CatalogueSource -import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchFilter -import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState +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.SourceFilter import eu.kanade.tachiyomi.util.system.LocaleHelper 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.VerticalDivider import tachiyomi.presentation.core.components.material.padding @Composable fun GlobalSearchScreen( - state: GlobalSearchState, + state: GlobalSearchScreenModel.State, items: Map, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, - onChangeFilter: (GlobalSearchFilter) -> Unit, + onChangeSearchFilter: (SourceFilter) -> Unit, + onToggleResults: () -> Unit, getManga: @Composable (Manga) -> State, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, @@ -71,13 +73,29 @@ fun GlobalSearchScreen( .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.searchFilter == GlobalSearchFilter.All, - onClick = { onChangeFilter(GlobalSearchFilter.All) }, + 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 = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -87,29 +105,15 @@ fun GlobalSearchScreen( }, ) - FilterChip( - selected = state.searchFilter == GlobalSearchFilter.PinnedOnly, - onClick = { onChangeFilter(GlobalSearchFilter.PinnedOnly) }, - leadingIcon = { - Icon( - imageVector = Icons.Outlined.PushPin, - contentDescription = "", - modifier = Modifier - .size(FilterChipDefaults.IconSize), - ) - }, - label = { - Text(text = stringResource(id = R.string.pinned_sources)) - }, - ) + VerticalDivider() FilterChip( - selected = state.searchFilter == GlobalSearchFilter.AvailableOnly, - onClick = { onChangeFilter(GlobalSearchFilter.AvailableOnly) }, + selected = state.onlyShowHasResults, + onClick = { onToggleResults() }, leadingIcon = { Icon( imageVector = Icons.Outlined.FilterList, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt index 01fb87e7e2..5b3ab28cf3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt @@ -29,10 +29,6 @@ object SettingsBrowseScreen : SearchableSettings { Preference.PreferenceGroup( title = stringResource(R.string.label_sources), preferenceItems = listOf( - Preference.PreferenceItem.SwitchPreference( - pref = sourcePreferences.searchPinnedSourcesOnly(), - title = stringResource(R.string.pref_search_pinned_sources_only), - ), Preference.PreferenceItem.SwitchPreference( pref = sourcePreferences.hideInLibraryItems(), title = stringResource(R.string.pref_hide_in_library_items), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt index 73ad967800..ae89d9cb00 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt @@ -10,6 +10,7 @@ import eu.kanade.presentation.browse.MigrateSearchScreen import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.ui.manga.MangaScreen +// TODO: this should probably be merged with GlobalSearchScreen somehow to dedupe logic class MigrateSearchScreen(private val mangaId: Long) : Screen() { @Composable diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt index 5f1999378c..78c449fd04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt @@ -63,7 +63,8 @@ class GlobalSearchScreen( onChangeSearchQuery = screenModel::updateSearchQuery, onSearch = screenModel::search, getManga = { screenModel.getManga(it) }, - onChangeFilter = screenModel::setFilter, + onChangeSearchFilter = screenModel::setSourceFilter, + onToggleResults = screenModel::toggleFilterResults, onClickSource = { if (!screenModel.incognitoMode.get()) { screenModel.lastUsedSourceId.set(it.id) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt index 7190987f6f..13ac004686 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt @@ -20,17 +20,17 @@ class GlobalSearchScreenModel( preferences: BasePreferences = Injekt.get(), private val sourcePreferences: SourcePreferences = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(), -) : SearchScreenModel(GlobalSearchState(searchQuery = initialQuery)) { +) : SearchScreenModel(State(searchQuery = initialQuery)) { val incognitoMode = preferences.incognitoMode() val lastUsedSourceId = sourcePreferences.lastUsedSource() - val searchPagerFlow = state.map { Pair(it.searchFilter, it.items) } + val searchPagerFlow = state.map { Pair(it.onlyShowHasResults, it.items) } .distinctUntilChanged() - .map { (filter, items) -> - items - .filter { (source, result) -> isSourceVisible(filter, source, result) } - }.stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items) + .map { (onlyShowHasResults, items) -> + items.filter { (_, result) -> result.isVisible(onlyShowHasResults) } + } + .stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items) init { extensionFilter = initialExtensionFilter @@ -45,19 +45,12 @@ class GlobalSearchScreenModel( val pinnedSources = sourcePreferences.pinnedSources().get() return sourceManager.getCatalogueSources() + .filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources } .filter { it.lang in enabledLanguages } .filterNot { "${it.id}" in disabledSources } .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" })) } - private fun isSourceVisible(filter: GlobalSearchFilter, source: CatalogueSource, result: SearchItemResult): Boolean { - return when (filter) { - GlobalSearchFilter.AvailableOnly -> result is SearchItemResult.Success && !result.isEmpty - GlobalSearchFilter.PinnedOnly -> "${source.id}" in sourcePreferences.pinnedSources().get() - GlobalSearchFilter.All -> true - } - } - override fun updateSearchQuery(query: String?) { mutableState.update { it.copy(searchQuery = query) @@ -70,27 +63,32 @@ class GlobalSearchScreenModel( } } - fun setFilter(filter: GlobalSearchFilter) { - mutableState.update { it.copy(searchFilter = filter) } - } - override fun getItems(): Map { return mutableState.value.items } -} - -enum class GlobalSearchFilter { - All, PinnedOnly, AvailableOnly -} - -@Immutable -data class GlobalSearchState( - val searchQuery: String? = null, - val searchFilter: GlobalSearchFilter = GlobalSearchFilter.All, - val items: Map = emptyMap(), -) { - - val progress: Int = items.count { it.value !is SearchItemResult.Loading } - - val total: Int = items.size + + fun setSourceFilter(filter: SourceFilter) { + mutableState.update { it.copy(sourceFilter = filter) } + } + + fun toggleFilterResults() { + mutableState.update { + it.copy(onlyShowHasResults = !it.onlyShowHasResults) + } + } + + private fun SearchItemResult.isVisible(onlyShowHasResults: Boolean): Boolean { + return !onlyShowHasResults || (this is SearchItemResult.Success && !this.isEmpty) + } + + @Immutable + data class State( + val searchQuery: String? = null, + val sourceFilter: SourceFilter = SourceFilter.PinnedOnly, + val onlyShowHasResults: Boolean = false, + val items: Map = emptyMap(), + ) { + val progress: Int = items.count { it.value !is SearchItemResult.Loading } + val total: Int = items.size + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 78238b21b8..26ab767c50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -68,16 +68,7 @@ abstract class SearchScreenModel( val enabledSources = getEnabledSources() if (filter.isEmpty()) { - val shouldSearchPinnedOnly = sourcePreferences.searchPinnedSourcesOnly().get() - val pinnedSources = sourcePreferences.pinnedSources().get() - - return enabledSources.filter { - if (shouldSearchPinnedOnly) { - "${it.id}" in pinnedSources - } else { - true - } - } + return enabledSources } return extensionManager.installedExtensionsFlow.value @@ -137,6 +128,11 @@ abstract class SearchScreenModel( } } +enum class SourceFilter { + All, + PinnedOnly, +} + sealed class SearchItemResult { object Loading : SearchItemResult() diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 6984ac54a6..3df318c7e9 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -480,7 +480,6 @@ Track - Only search pinned sources in global search Hide entries already in library