Change search result order for all other categories
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user