Change search result order for all other categories
This commit is contained in:
parent
bf6e963545
commit
774777f79c
@ -9,7 +9,6 @@ import de.mm20.launcher2.devicepose.DevicePoseProvider
|
|||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
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.CalendarSearchSettings
|
||||||
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
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.Contact
|
||||||
import de.mm20.launcher2.search.File
|
import de.mm20.launcher2.search.File
|
||||||
import de.mm20.launcher2.search.Location
|
import de.mm20.launcher2.search.Location
|
||||||
|
import de.mm20.launcher2.search.ResultScore
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.SearchFilters
|
import de.mm20.launcher2.search.SearchFilters
|
||||||
import de.mm20.launcher2.search.SearchService
|
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.Website
|
||||||
import de.mm20.launcher2.search.data.Calculator
|
import de.mm20.launcher2.search.data.Calculator
|
||||||
import de.mm20.launcher2.search.data.UnitConverter
|
import de.mm20.launcher2.search.data.UnitConverter
|
||||||
|
import de.mm20.launcher2.search.isUnspecified
|
||||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||||
import de.mm20.launcher2.searchable.VisibilityLevel
|
import de.mm20.launcher2.searchable.VisibilityLevel
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
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.first
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -264,138 +264,136 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val hiddenItemKeys = if (!filters.hiddenItems) searchableRepository.getKeys(
|
val hiddenItemKeys = if (!filters.hiddenItems) searchableRepository.getKeys(
|
||||||
maxVisibility = VisibilityLevel.Hidden,
|
maxVisibility = VisibilityLevel.Hidden,
|
||||||
) else flowOf(emptyList())
|
) else flowOf(emptyList())
|
||||||
searchUiSettings.resultOrder.collectLatest { resultOrder ->
|
searchService.search(
|
||||||
searchService.search(
|
query,
|
||||||
query,
|
filters = if (query.isEmpty()) filters.copy(apps = true) else filters,
|
||||||
filters = if (query.isEmpty()) filters.copy(apps = true) else filters,
|
)
|
||||||
)
|
.combine(hiddenItemKeys) { results, hiddenKeys -> results to hiddenKeys }
|
||||||
.combine(hiddenItemKeys) { results, hiddenKeys -> results to hiddenKeys }
|
.collectLatest { (results, hiddenKeys) ->
|
||||||
.collectLatest { (results, hiddenKeys) ->
|
val hiddenItems = mutableListOf<SavableSearchable>()
|
||||||
val hiddenItems = mutableListOf<SavableSearchable>()
|
|
||||||
|
|
||||||
if (results.apps != null) {
|
if (results.apps != null) {
|
||||||
val (hiddenApps, apps) = results.apps!!.partition {
|
val (hiddenApps, apps) = results.apps!!.partition {
|
||||||
hiddenKeys.contains(
|
hiddenKeys.contains(
|
||||||
it.key
|
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
|
|
||||||
}
|
}
|
||||||
|
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
|
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
|
if (size <= 1) return this
|
||||||
val sequence = asSequence()
|
val sequence = asSequence()
|
||||||
val weights = searchableRepository.getWeights(map { it.key }).first()
|
val weights = searchableRepository.getWeights(map { it.key }).first()
|
||||||
@ -477,10 +475,22 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val aWeight = weights[a.key] ?: 0.0
|
val aWeight = weights[a.key] ?: 0.0
|
||||||
val bWeight = weights[b.key] ?: 0.0
|
val bWeight = weights[b.key] ?: 0.0
|
||||||
|
|
||||||
val aScore = a.score.score * 0.7f + aWeight.toFloat() * 0.3f
|
val aScore = if (a.score.isUnspecified) {
|
||||||
val bScore = b.score.score * 0.7f + bWeight.toFloat() * 0.3f
|
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()
|
return sorted.distinctBy { it.key }.toList()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ value class ResultScore private constructor(private val packed: Long) : Comparab
|
|||||||
* A total score for the result, combining the similarity with additional factors.
|
* A total score for the result, combining the similarity with additional factors.
|
||||||
*/
|
*/
|
||||||
val score: Float
|
val score: Float
|
||||||
get() = (similarity + (if (isPrefix) 0.8f else 0f) + (if (isSubstring) 0.8f else 0f)) * (if (isPrimary) 1f else 0.5f)
|
get() = (similarity + (if (isPrefix) 0.8f else 0f) + (if (isSubstring) 0.8f else 0f)) * (if (isPrimary) 1f else 0.8f)
|
||||||
|
|
||||||
override fun compareTo(other: ResultScore): Int {
|
override fun compareTo(other: ResultScore): Int {
|
||||||
return score.compareTo(other.score)
|
return score.compareTo(other.score)
|
||||||
@ -89,6 +89,15 @@ value class ResultScore private constructor(private val packed: Long) : Comparab
|
|||||||
isPrimary = false,
|
isPrimary = false,
|
||||||
similarity = 0f
|
similarity = 0f
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
|
val Unspecified = ResultScore(
|
||||||
|
isPrefix = false,
|
||||||
|
isSubstring = false,
|
||||||
|
isPrimary = false,
|
||||||
|
similarity = Float.NaN,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline val ResultScore.isUnspecified : Boolean
|
||||||
|
get() = this == ResultScore.Unspecified
|
||||||
@ -4,5 +4,5 @@ import kotlinx.coroutines.Deferred
|
|||||||
|
|
||||||
interface Searchable {
|
interface Searchable {
|
||||||
val score: ResultScore
|
val score: ResultScore
|
||||||
get() = ResultScore.Zero
|
get() = ResultScore.Unspecified
|
||||||
}
|
}
|
||||||
@ -264,14 +264,6 @@ internal class AppRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun matches(label: String, query: String): Boolean {
|
|
||||||
val normalizedLabel = label.normalize()
|
|
||||||
val normalizedQuery = query.normalize()
|
|
||||||
if (normalizedLabel.contains(normalizedQuery)) return true
|
|
||||||
val fuzzyScore = FuzzyScore(Locale.getDefault())
|
|
||||||
return fuzzyScore.fuzzyScore(normalizedLabel, normalizedQuery) >= query.length * 1.5
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getActivityByComponentName(componentName: ComponentName?): LauncherApp? {
|
private fun getActivityByComponentName(componentName: ComponentName?): LauncherApp? {
|
||||||
componentName ?: return null
|
componentName ?: return null
|
||||||
val intent = Intent().setComponent(componentName)
|
val intent = Intent().setComponent(componentName)
|
||||||
|
|||||||
@ -41,7 +41,7 @@ internal data class LauncherApp(
|
|||||||
override val isSuspended: Boolean = false,
|
override val isSuspended: Boolean = false,
|
||||||
internal val userSerialNumber: Long,
|
internal val userSerialNumber: Long,
|
||||||
override val labelOverride: String? = null,
|
override val labelOverride: String? = null,
|
||||||
override val score: ResultScore = ResultScore.Zero,
|
override val score: ResultScore = ResultScore.Unspecified,
|
||||||
) : Application {
|
) : Application {
|
||||||
|
|
||||||
override val componentName: ComponentName
|
override val componentName: ComponentName
|
||||||
@ -50,7 +50,7 @@ internal data class LauncherApp(
|
|||||||
override val label: String = launcherActivityInfo.label.toString()
|
override val label: String = launcherActivityInfo.label.toString()
|
||||||
|
|
||||||
|
|
||||||
constructor(context: Context, launcherActivityInfo: LauncherActivityInfo, score: ResultScore = ResultScore.Zero) : this(
|
constructor(context: Context, launcherActivityInfo: LauncherActivityInfo, score: ResultScore = ResultScore.Unspecified) : this(
|
||||||
launcherActivityInfo,
|
launcherActivityInfo,
|
||||||
versionName = getPackageVersionName(context, launcherActivityInfo.applicationInfo.packageName),
|
versionName = getPackageVersionName(context, launcherActivityInfo.applicationInfo.packageName),
|
||||||
isSuspended = launcherActivityInfo.applicationInfo.flags and ApplicationInfo.FLAG_SUSPENDED != 0,
|
isSuspended = launcherActivityInfo.applicationInfo.flags and ApplicationInfo.FLAG_SUSPENDED != 0,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import de.mm20.launcher2.permissions.PermissionGroup
|
|||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
import de.mm20.launcher2.search.AppShortcut
|
import de.mm20.launcher2.search.AppShortcut
|
||||||
|
import de.mm20.launcher2.search.ResultScore
|
||||||
import de.mm20.launcher2.search.SearchableRepository
|
import de.mm20.launcher2.search.SearchableRepository
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
@ -141,22 +142,20 @@ internal class AppShortcutRepositoryImpl(
|
|||||||
LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
|
LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
|
||||||
)
|
)
|
||||||
val shortcuts = launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle())
|
val shortcuts = launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle())
|
||||||
?.filter {
|
?.mapNotNull {
|
||||||
if (it.longLabel != null) {
|
val score = ResultScore(
|
||||||
return@filter matches(it.longLabel.toString(), query)
|
query = query,
|
||||||
}
|
primaryFields = listOfNotNull(it.longLabel?.toString(), it.shortLabel?.toString())
|
||||||
if (it.shortLabel != null) {
|
)
|
||||||
return@filter matches(it.shortLabel.toString(), query)
|
if (score.score < 0.8f) return@mapNotNull null
|
||||||
}
|
LauncherShortcut(
|
||||||
return@filter false
|
context,
|
||||||
|
it,
|
||||||
|
score
|
||||||
|
)
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
|
|
||||||
shortcuts.mapNotNull {
|
shortcuts.toImmutableList()
|
||||||
LauncherShortcut(
|
|
||||||
context,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}.toImmutableList()
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
persistentListOf()
|
persistentListOf()
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import de.mm20.launcher2.icons.*
|
|||||||
import de.mm20.launcher2.ktx.getSerialNumber
|
import de.mm20.launcher2.ktx.getSerialNumber
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.search.AppShortcut
|
import de.mm20.launcher2.search.AppShortcut
|
||||||
|
import de.mm20.launcher2.search.ResultScore
|
||||||
import de.mm20.launcher2.search.SearchableSerializer
|
import de.mm20.launcher2.search.SearchableSerializer
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -32,6 +33,7 @@ internal data class LauncherShortcut(
|
|||||||
override val appName: String?,
|
override val appName: String?,
|
||||||
internal val userSerialNumber: Long,
|
internal val userSerialNumber: Long,
|
||||||
override val labelOverride: String? = null,
|
override val labelOverride: String? = null,
|
||||||
|
override val score: ResultScore = ResultScore.Unspecified,
|
||||||
) : AppShortcut {
|
) : AppShortcut {
|
||||||
|
|
||||||
override val domain: String = Domain
|
override val domain: String = Domain
|
||||||
@ -47,6 +49,7 @@ internal data class LauncherShortcut(
|
|||||||
constructor(
|
constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
launcherShortcut: ShortcutInfo,
|
launcherShortcut: ShortcutInfo,
|
||||||
|
score: ResultScore = ResultScore.Unspecified,
|
||||||
): this(
|
): this(
|
||||||
launcherShortcut = launcherShortcut,
|
launcherShortcut = launcherShortcut,
|
||||||
appName = try {
|
appName = try {
|
||||||
@ -55,7 +58,8 @@ internal data class LauncherShortcut(
|
|||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
null
|
null
|
||||||
},
|
},
|
||||||
userSerialNumber = launcherShortcut.userHandle.getSerialNumber(context)
|
userSerialNumber = launcherShortcut.userHandle.getSerialNumber(context),
|
||||||
|
score = score,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val label: String
|
override val label: String
|
||||||
|
|||||||
@ -87,7 +87,7 @@ class PluginFileProvider(
|
|||||||
uri = cursor[FileColumns.ContentUri]?.let { Uri.parse(it) } ?: continue,
|
uri = cursor[FileColumns.ContentUri]?.let { Uri.parse(it) } ?: continue,
|
||||||
thumbnailUri = cursor[FileColumns.ThumbnailUri]?.let { Uri.parse(it) },
|
thumbnailUri = cursor[FileColumns.ThumbnailUri]?.let { Uri.parse(it) },
|
||||||
storageStrategy = config.storageStrategy,
|
storageStrategy = config.storageStrategy,
|
||||||
isDirectory = cursor[FileColumns.IsDirectory] ?: false,
|
isDirectory = cursor[FileColumns.IsDirectory] == true,
|
||||||
authority = pluginAuthority,
|
authority = pluginAuthority,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
updatedSelf = {
|
updatedSelf = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user