Cleanup extension screen search query predicate

(cherry picked from commit e059190fabe3cbe8498fc3cec7e39b0350f3c289)
This commit is contained in:
AntsyLich
2025-12-27 01:34:00 +06:00
committed by Jobobby04
parent a9fe971337
commit 976b5cc03e
@@ -50,79 +50,46 @@ class ExtensionsScreenModel(
ExtensionUiModel.Item(it, map[it.pkgName] ?: InstallStep.Idle)
}
}
val queryFilter: (String) -> ((Extension) -> Boolean) = { query ->
filter@{ extension ->
if (query.isEmpty()) return@filter true
query.split(",").any { _input ->
val input = _input.trim()
if (input.isEmpty()) return@any false
when (extension) {
is Extension.Available -> {
extension.sources.any {
it.name.contains(input, ignoreCase = true) ||
it.baseUrl.contains(input, ignoreCase = true) ||
it.id == input.toLongOrNull()
} ||
extension.name.contains(input, ignoreCase = true)
}
is Extension.Installed -> {
extension.sources.any {
it.name.contains(input, ignoreCase = true) ||
it.id == input.toLongOrNull() ||
if (it is HttpSource) {
it.baseUrl.contains(input, ignoreCase = true)
} else {
false
}
} ||
extension.name.contains(input, ignoreCase = true)
}
is Extension.Untrusted -> extension.name.contains(input, ignoreCase = true)
}
}
}
}
screenModelScope.launchIO {
combine(
state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
state.map { it.searchQuery }
.distinctUntilChanged()
.debounce(SEARCH_DEBOUNCE_MILLIS)
.map { searchQueryPredicate(it ?: "") },
currentDownloads,
getExtensions.subscribe(),
) { query, downloads, (_updates, _installed, _available, _untrusted) ->
val searchQuery = query ?: ""
val itemsGroups: ItemGroups = mutableMapOf()
val updates = _updates.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
if (updates.isNotEmpty()) {
itemsGroups[ExtensionUiModel.Header.Resource(MR.strings.ext_updates_pending)] = updates
}
val installed = _installed.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
val untrusted = _untrusted.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
if (installed.isNotEmpty() || untrusted.isNotEmpty()) {
itemsGroups[ExtensionUiModel.Header.Resource(MR.strings.ext_installed)] = installed + untrusted
}
val languagesWithExtensions = _available
.filter(queryFilter(searchQuery))
.groupBy { it.lang }
.toSortedMap(LocaleHelper.comparator)
.map { (lang, exts) ->
ExtensionUiModel.Header.Text(LocaleHelper.getSourceDisplayName(lang, context)) to
exts.map(extensionMapper(downloads))
) { predicate, downloads, (_updates, _installed, _available, _untrusted) ->
buildMap {
val updates = _updates.filter(predicate).map(extensionMapper(downloads))
if (updates.isNotEmpty()) {
put(ExtensionUiModel.Header.Resource(MR.strings.ext_updates_pending), updates)
}
if (languagesWithExtensions.isNotEmpty()) {
itemsGroups.putAll(languagesWithExtensions)
}
itemsGroups
val installed = _installed.filter(predicate).map(extensionMapper(downloads))
val untrusted = _untrusted.filter(predicate).map(extensionMapper(downloads))
if (installed.isNotEmpty() || untrusted.isNotEmpty()) {
put(ExtensionUiModel.Header.Resource(MR.strings.ext_installed), installed + untrusted)
}
val languagesWithExtensions = _available
.filter(predicate)
.groupBy { it.lang }
.toSortedMap(LocaleHelper.comparator)
.map { (lang, exts) ->
ExtensionUiModel.Header.Text(LocaleHelper.getSourceDisplayName(lang, context)) to
exts.map(extensionMapper(downloads))
}
if (languagesWithExtensions.isNotEmpty()) {
putAll(languagesWithExtensions)
}
}
}
.collectLatest {
.collectLatest { items ->
mutableState.update { state ->
state.copy(
isLoading = false,
items = it,
items = items,
)
}
}
@@ -139,6 +106,36 @@ class ExtensionsScreenModel(
.launchIn(screenModelScope)
}
fun searchQueryPredicate(query: String): (Extension) -> Boolean {
val subqueries = query.split(",")
.map { it.trim() }
.filterNot { it.isBlank() }
if (subqueries.isEmpty()) return { true }
return { extension ->
subqueries.any { subquery ->
if (extension.name.contains(subquery, ignoreCase = true)) return@any true
when (extension) {
is Extension.Installed -> extension.sources.any { source ->
source.name.contains(subquery, ignoreCase = true) ||
(source as? HttpSource)?.baseUrl?.contains(subquery, ignoreCase = true) == true ||
source.id == subquery.toLongOrNull()
}
is Extension.Available -> extension.sources.any {
it.name.contains(subquery, ignoreCase = true) ||
it.baseUrl.contains(subquery, ignoreCase = true) ||
it.id == subquery.toLongOrNull()
}
else -> false
}
}
}
}
fun search(query: String?) {
mutableState.update {
it.copy(searchQuery = query)
@@ -222,7 +219,7 @@ class ExtensionsScreenModel(
}
}
typealias ItemGroups = MutableMap<ExtensionUiModel.Header, List<ExtensionUiModel.Item>>
typealias ItemGroups = Map<ExtensionUiModel.Header, List<ExtensionUiModel.Item>>
object ExtensionUiModel {
sealed interface Header {