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