Change search result order for all other categories

This commit is contained in:
MM20
2024-10-13 20:32:15 +02:00
parent bf6e963545
commit 774777f79c
8 changed files with 179 additions and 165 deletions
@@ -9,7 +9,6 @@ import de.mm20.launcher2.devicepose.DevicePoseProvider
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.SearchResultOrder
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
import de.mm20.launcher2.preferences.search.ContactSearchSettings
import de.mm20.launcher2.preferences.search.FileSearchSettings
@@ -26,6 +25,7 @@ import de.mm20.launcher2.search.CalendarEvent
import de.mm20.launcher2.search.Contact
import de.mm20.launcher2.search.File
import de.mm20.launcher2.search.Location
import de.mm20.launcher2.search.ResultScore
import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.search.SearchFilters
import de.mm20.launcher2.search.SearchService
@@ -33,6 +33,7 @@ import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.Website
import de.mm20.launcher2.search.data.Calculator
import de.mm20.launcher2.search.data.UnitConverter
import de.mm20.launcher2.search.isUnspecified
import de.mm20.launcher2.searchable.SavableSearchableRepository
import de.mm20.launcher2.searchable.VisibilityLevel
import de.mm20.launcher2.searchactions.actions.SearchAction
@@ -46,7 +47,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -264,138 +264,136 @@ class SearchVM : ViewModel(), KoinComponent {
val hiddenItemKeys = if (!filters.hiddenItems) searchableRepository.getKeys(
maxVisibility = VisibilityLevel.Hidden,
) else flowOf(emptyList())
searchUiSettings.resultOrder.collectLatest { resultOrder ->
searchService.search(
query,
filters = if (query.isEmpty()) filters.copy(apps = true) else filters,
)
.combine(hiddenItemKeys) { results, hiddenKeys -> results to hiddenKeys }
.collectLatest { (results, hiddenKeys) ->
val hiddenItems = mutableListOf<SavableSearchable>()
searchService.search(
query,
filters = if (query.isEmpty()) filters.copy(apps = true) else filters,
)
.combine(hiddenItemKeys) { results, hiddenKeys -> results to hiddenKeys }
.collectLatest { (results, hiddenKeys) ->
val hiddenItems = mutableListOf<SavableSearchable>()
if (results.apps != null) {
val (hiddenApps, apps) = results.apps!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenApps
appResults.value = apps.applyRanking(resultOrder)
} else {
appResults.value = emptyList()
}
workAppResults.value = emptyList()
privateSpaceAppResults.value = emptyList()
if (results.shortcuts != null) {
val (hiddenShortcuts, shortcuts) = results.shortcuts!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenShortcuts
appShortcutResults.value = shortcuts.applyRanking(resultOrder)
} else {
appShortcutResults.value = emptyList()
}
if (results.files != null) {
val (hiddenFiles, files) = results.files!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenFiles
fileResults.value = files.applyRanking(resultOrder)
} else {
fileResults.value = emptyList()
}
if (results.contacts != null) {
val (hiddenContacts, contacts) = results.contacts!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenContacts
contactResults.value = contacts.applyRanking(resultOrder)
} else {
contactResults.value = emptyList()
}
if (results.calendars != null) {
val (hiddenEvents, events) = results.calendars!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenEvents
calendarResults.value = events.applyRanking(resultOrder)
} else {
calendarResults.value = emptyList()
}
if (results.locations != null && results.locations!!.isNotEmpty()) {
val (hiddenLocations, locations) = results.locations!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenLocations
val lastLocation = devicePoseProvider.lastLocation
if (lastLocation != null) {
locationResults.value = locations.asSequence()
.sortedWith { a, b ->
a.distanceTo(lastLocation)
.compareTo(b.distanceTo(lastLocation))
}
.distinctBy { it.key }
.toList()
} else {
locationResults.value = locations.applyRanking(resultOrder)
}
} else {
locationResults.value = emptyList()
}
if (results.wikipedia != null) {
articleResults.value = results.wikipedia!!.applyRanking(resultOrder)
} else {
articleResults.value = emptyList()
}
if (results.websites != null) {
websiteResults.value = results.websites!!.applyRanking(resultOrder)
} else {
websiteResults.value = emptyList()
}
calculatorResults.value = results.calculators ?: emptyList()
unitConverterResults.value = results.unitConverters ?: emptyList()
if (results.searchActions != null) {
searchActionResults.value = results.searchActions!!
}
if (launchOnEnter.value) {
bestMatch.value = when {
appResults.value.isNotEmpty() -> appResults.value.first()
appShortcutResults.value.isNotEmpty() -> appShortcutResults.value.first()
calendarResults.value.isNotEmpty() -> calendarResults.value.first()
locationResults.value.isNotEmpty() -> locationResults.value.first()
contactResults.value.isNotEmpty() -> contactResults.value.first()
articleResults.value.isNotEmpty() -> articleResults.value.first()
websiteResults.value.isNotEmpty() -> websiteResults.value.first()
fileResults.value.isNotEmpty() -> fileResults.value.first()
searchActionResults.value.isNotEmpty() -> searchActionResults.value.first()
else -> null
}
} else {
bestMatch.value = null
if (results.apps != null) {
val (hiddenApps, apps) = results.apps!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenApps
appResults.value = apps.applyRanking(query)
} else {
appResults.value = emptyList()
}
}
workAppResults.value = emptyList()
privateSpaceAppResults.value = emptyList()
if (results.shortcuts != null) {
val (hiddenShortcuts, shortcuts) = results.shortcuts!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenShortcuts
appShortcutResults.value = shortcuts.applyRanking(query)
} else {
appShortcutResults.value = emptyList()
}
if (results.files != null) {
val (hiddenFiles, files) = results.files!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenFiles
fileResults.value = files.applyRanking(query)
} else {
fileResults.value = emptyList()
}
if (results.contacts != null) {
val (hiddenContacts, contacts) = results.contacts!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenContacts
contactResults.value = contacts.applyRanking(query)
} else {
contactResults.value = emptyList()
}
if (results.calendars != null) {
val (hiddenEvents, events) = results.calendars!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenEvents
calendarResults.value = events.applyRanking(query)
} else {
calendarResults.value = emptyList()
}
if (results.locations != null && results.locations!!.isNotEmpty()) {
val (hiddenLocations, locations) = results.locations!!.partition {
hiddenKeys.contains(
it.key
)
}
hiddenItems += hiddenLocations
val lastLocation = devicePoseProvider.lastLocation
if (lastLocation != null) {
locationResults.value = locations.asSequence()
.sortedWith { a, b ->
a.distanceTo(lastLocation)
.compareTo(b.distanceTo(lastLocation))
}
.distinctBy { it.key }
.toList()
} else {
locationResults.value = locations.applyRanking(query)
}
} else {
locationResults.value = emptyList()
}
if (results.wikipedia != null) {
articleResults.value = results.wikipedia!!.applyRanking(query)
} else {
articleResults.value = emptyList()
}
if (results.websites != null) {
websiteResults.value = results.websites!!.applyRanking(query)
} else {
websiteResults.value = emptyList()
}
calculatorResults.value = results.calculators ?: emptyList()
unitConverterResults.value = results.unitConverters ?: emptyList()
if (results.searchActions != null) {
searchActionResults.value = results.searchActions!!
}
if (launchOnEnter.value) {
bestMatch.value = when {
appResults.value.isNotEmpty() -> appResults.value.first()
appShortcutResults.value.isNotEmpty() -> appShortcutResults.value.first()
calendarResults.value.isNotEmpty() -> calendarResults.value.first()
locationResults.value.isNotEmpty() -> locationResults.value.first()
contactResults.value.isNotEmpty() -> contactResults.value.first()
articleResults.value.isNotEmpty() -> articleResults.value.first()
websiteResults.value.isNotEmpty() -> websiteResults.value.first()
fileResults.value.isNotEmpty() -> fileResults.value.first()
searchActionResults.value.isNotEmpty() -> searchActionResults.value.first()
else -> null
}
} else {
bestMatch.value = null
}
}
}
}
}
@@ -469,7 +467,7 @@ class SearchVM : ViewModel(), KoinComponent {
expandedCategory.value = category
}
private suspend fun <T : SavableSearchable> List<T>.applyRanking(order: SearchResultOrder): List<T> {
private suspend fun <T : SavableSearchable> List<T>.applyRanking(query: String): List<T> {
if (size <= 1) return this
val sequence = asSequence()
val weights = searchableRepository.getWeights(map { it.key }).first()
@@ -477,10 +475,22 @@ class SearchVM : ViewModel(), KoinComponent {
val aWeight = weights[a.key] ?: 0.0
val bWeight = weights[b.key] ?: 0.0
val aScore = a.score.score * 0.7f + aWeight.toFloat() * 0.3f
val bScore = b.score.score * 0.7f + bWeight.toFloat() * 0.3f
val aScore = if (a.score.isUnspecified) {
ResultScore(query = query, primaryFields = listOf(a.labelOverride ?: a.label)).score
} else {
a.score.score
}
bScore.compareTo(aScore)
val bScore = if (b.score.isUnspecified) {
ResultScore(query = query, primaryFields = listOf(b.labelOverride ?: b.label)).score
} else {
b.score.score
}
val aTotal = aScore * 0.7f + aWeight.toFloat() * 0.3f
val bTotal = bScore * 0.7f + bWeight.toFloat() * 0.3f
bTotal.compareTo(aTotal)
}
return sorted.distinctBy { it.key }.toList()
}