Add filtering options for pinned sources and empty results in search menu
This commit is contained in:
committed by
Koitharu
parent
5701862661
commit
119b7c2ac7
@@ -94,7 +94,7 @@ class SearchActivity :
|
||||
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
|
||||
supportActionBar?.setSubtitle(R.string.search_results)
|
||||
|
||||
addMenuProvider(SearchKindMenuProvider(this, viewModel.query, viewModel.kind))
|
||||
addMenuProvider(SearchKindMenuProvider(this, viewModel, viewModel.query, viewModel.kind))
|
||||
|
||||
viewModel.list.observe(this, adapter)
|
||||
viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
|
||||
|
||||
@@ -11,8 +11,9 @@ import org.koitharu.kotatsu.search.domain.SearchKind
|
||||
|
||||
class SearchKindMenuProvider(
|
||||
private val activity: SearchActivity,
|
||||
private val viewModel: SearchViewModel,
|
||||
private val query: String,
|
||||
private val kind: SearchKind
|
||||
private val kind: SearchKind,
|
||||
) : MenuProvider {
|
||||
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
@@ -32,6 +33,20 @@ class SearchKindMenuProvider(
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_filter_pinned_only -> {
|
||||
menuItem.isChecked = !menuItem.isChecked
|
||||
viewModel.setPinnedOnly(menuItem.isChecked)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_filter_hide_empty -> {
|
||||
menuItem.isChecked = !menuItem.isChecked
|
||||
viewModel.setHideEmpty(menuItem.isChecked)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val newKind = when (menuItem.itemId) {
|
||||
R.id.action_kind_simple -> SearchKind.SIMPLE
|
||||
R.id.action_kind_title -> SearchKind.TITLE
|
||||
|
||||
@@ -62,6 +62,8 @@ class SearchViewModel @Inject constructor(
|
||||
val kind = savedStateHandle.get<SearchKind>(AppRouter.KEY_KIND) ?: SearchKind.SIMPLE
|
||||
|
||||
private var includeDisabledSources = MutableStateFlow(false)
|
||||
private var pinnedOnly = MutableStateFlow(false)
|
||||
private var hideEmpty = MutableStateFlow(false)
|
||||
private val results = MutableStateFlow<List<SearchResultsListModel>>(emptyList())
|
||||
|
||||
private var searchJob: Job? = null
|
||||
@@ -70,9 +72,15 @@ class SearchViewModel @Inject constructor(
|
||||
results,
|
||||
isLoading.dropWhile { !it },
|
||||
includeDisabledSources,
|
||||
) { list, loading, includeDisabled ->
|
||||
hideEmpty,
|
||||
) { list, loading, includeDisabled, hideEmptyVal ->
|
||||
val filteredList = if (hideEmptyVal) {
|
||||
list.filter { it.list.isNotEmpty() }
|
||||
} else {
|
||||
list
|
||||
}
|
||||
when {
|
||||
list.isEmpty() -> listOf(
|
||||
filteredList.isEmpty() -> listOf(
|
||||
when {
|
||||
loading -> LoadingState
|
||||
else -> EmptyState(
|
||||
@@ -84,9 +92,9 @@ class SearchViewModel @Inject constructor(
|
||||
},
|
||||
)
|
||||
|
||||
loading -> list + LoadingFooter()
|
||||
includeDisabled -> list
|
||||
else -> list + ButtonFooter(R.string.search_disabled_sources)
|
||||
loading -> filteredList + LoadingFooter()
|
||||
includeDisabled -> filteredList
|
||||
else -> filteredList + ButtonFooter(R.string.search_disabled_sources)
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
|
||||
|
||||
@@ -114,6 +122,17 @@ class SearchViewModel @Inject constructor(
|
||||
doSearch()
|
||||
}
|
||||
|
||||
fun setPinnedOnly(value: Boolean) {
|
||||
if (pinnedOnly.value != value) {
|
||||
pinnedOnly.value = value
|
||||
retry()
|
||||
}
|
||||
}
|
||||
|
||||
fun setHideEmpty(value: Boolean) {
|
||||
hideEmpty.value = value
|
||||
}
|
||||
|
||||
fun continueSearch() {
|
||||
if (includeDisabledSources.value) {
|
||||
return
|
||||
@@ -122,8 +141,12 @@ class SearchViewModel @Inject constructor(
|
||||
searchJob = launchLoadingJob(Dispatchers.Default) {
|
||||
includeDisabledSources.value = true
|
||||
prevJob?.join()
|
||||
val sources = sourcesRepository.getDisabledSources()
|
||||
.sortedByDescending { it.priority() }
|
||||
val sources = if (pinnedOnly.value) {
|
||||
emptyList()
|
||||
} else {
|
||||
sourcesRepository.getDisabledSources()
|
||||
.sortedByDescending { it.priority() }
|
||||
}
|
||||
val semaphore = Semaphore(MAX_PARALLELISM)
|
||||
sources.map { source ->
|
||||
launch {
|
||||
@@ -142,7 +165,11 @@ class SearchViewModel @Inject constructor(
|
||||
appendResult(searchHistory())
|
||||
appendResult(searchFavorites())
|
||||
appendResult(searchLocal())
|
||||
val sources = sourcesRepository.getEnabledSources()
|
||||
val sources = if (pinnedOnly.value) {
|
||||
sourcesRepository.getPinnedSources().toList()
|
||||
} else {
|
||||
sourcesRepository.getEnabledSources()
|
||||
}
|
||||
val semaphore = Semaphore(MAX_PARALLELISM)
|
||||
sources.map { source ->
|
||||
launch {
|
||||
|
||||
@@ -33,6 +33,20 @@
|
||||
android:title="@string/genre" />
|
||||
|
||||
</group>
|
||||
|
||||
<group android:id="@+id/group_search_filters">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_filter_pinned_only"
|
||||
android:checkable="true"
|
||||
android:title="@string/pinned_sources_only" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_filter_hide_empty"
|
||||
android:checkable="true"
|
||||
android:title="@string/hide_empty_sources" />
|
||||
|
||||
</group>
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
@@ -210,6 +210,8 @@
|
||||
<string name="disabled">Disabled</string>
|
||||
<string name="reset_filter">Reset filter</string>
|
||||
<string name="enter_name">Enter name</string>
|
||||
<string name="pinned_sources_only">Pinned sources only</string>
|
||||
<string name="hide_empty_sources">Hide empty sources</string>
|
||||
<string name="onboard_text">Select languages which you want to read manga. You can change it later in settings.</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="only_using_wifi">Only on Wi-Fi</string>
|
||||
|
||||
Reference in New Issue
Block a user