Sort chinese apps by their pinyin transliteration

Close #61
This commit is contained in:
MM20 2022-06-12 15:48:43 +02:00
parent a064e800b6
commit b436f75f17
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
7 changed files with 40 additions and 24 deletions

View File

@ -45,8 +45,6 @@ dependencies {
implementation(libs.commons.text) implementation(libs.commons.text)
implementation(libs.tinypinyin)
implementation(project(":search")) implementation(project(":search"))
implementation(project(":base")) implementation(project(":base"))
implementation(project(":preferences")) implementation(project(":preferences"))

View File

@ -5,15 +5,13 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.content.pm.PackageInstaller
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Process import android.os.Process
import android.os.UserHandle import android.os.UserHandle
import android.util.Log import android.util.Log
import com.github.promeg.pinyinhelper.Pinyin import de.mm20.launcher2.ktx.normalize
import de.mm20.launcher2.search.data.AppInstallation
import de.mm20.launcher2.search.data.Application import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.data.LauncherApp import de.mm20.launcher2.search.data.LauncherApp
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -170,14 +168,10 @@ internal class AppRepositoryImpl(
} }
private fun matches(label: String, query: String): Boolean { private fun matches(label: String, query: String): Boolean {
val labelLatin = romanize(label) val normalizedLabel = label.normalize()
val fuzzyScore = FuzzyScore(Locale.getDefault()) val fuzzyScore = FuzzyScore(Locale.getDefault())
return fuzzyScore.fuzzyScore(label, query) >= query.length * 1.5 || return fuzzyScore.fuzzyScore(label, query) >= query.length * 1.5 ||
fuzzyScore.fuzzyScore(labelLatin, query) >= query.length * 1.5 fuzzyScore.fuzzyScore(normalizedLabel, query.normalize()) >= query.length * 1.5
}
private fun romanize(label: String): String {
return Pinyin.toPinyin(label, "").lowercase(Locale.getDefault())
} }
private fun getActivityByComponentName(componentName: ComponentName?): Application? { private fun getActivityByComponentName(componentName: ComponentName?): Application? {

View File

@ -42,7 +42,6 @@ dependencies {
implementation(libs.koin.android) implementation(libs.koin.android)
implementation(libs.commons.text) implementation(libs.commons.text)
implementation(libs.tinypinyin)
implementation(project(":search")) implementation(project(":search"))
implementation(project(":permissions")) implementation(project(":permissions"))

View File

@ -6,7 +6,8 @@ import android.content.pm.LauncherApps
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Process import android.os.Process
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import com.github.promeg.pinyinhelper.Pinyin import de.mm20.launcher2.ktx.normalize
import de.mm20.launcher2.ktx.romanize
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.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
@ -128,13 +129,9 @@ internal class AppShortcutRepositoryImpl(
private fun matches(label: String, query: String): Boolean { private fun matches(label: String, query: String): Boolean {
val labelLatin = romanize(label) val labelLatin = label.normalize()
val fuzzyScore = FuzzyScore(Locale.getDefault()) val fuzzyScore = FuzzyScore(Locale.getDefault())
return fuzzyScore.fuzzyScore(label, query) >= query.length * 1.5 || return fuzzyScore.fuzzyScore(label, query) >= query.length * 1.5 ||
fuzzyScore.fuzzyScore(labelLatin, query) >= query.length * 1.5 fuzzyScore.fuzzyScore(labelLatin, query.normalize()) >= query.length * 1.5
}
private fun romanize(label: String): String {
return Pinyin.toPinyin(label, "").lowercase(Locale.getDefault())
} }
} }

View File

@ -38,6 +38,7 @@ dependencies {
implementation(libs.bundles.kotlin) implementation(libs.bundles.kotlin)
implementation(libs.androidx.core) implementation(libs.androidx.core)
implementation(libs.tinypinyin)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.bundles.androidx.lifecycle) implementation(libs.bundles.androidx.lifecycle)

View File

@ -1,7 +1,25 @@
package de.mm20.launcher2.ktx package de.mm20.launcher2.ktx
import com.github.promeg.pinyinhelper.Pinyin
import java.net.URLDecoder import java.net.URLDecoder
import java.util.*
fun String.decodeUrl(charset: String): String? { fun String.decodeUrl(charset: String): String? {
return URLDecoder.decode(this, charset) return URLDecoder.decode(this, charset)
} }
/**
* Normalize a string to lowercase ASCII
* TODO: Only supports Chinese/Pinyin at the moment
*/
fun String.normalize(): String {
return this.romanize().lowercase(Locale.getDefault())
}
/**
* Romanize a string, transliterate non-latin characters into latin
* TODO: Only supports Chinese/Pinyin at the moment
*/
fun String.romanize(): String {
return Pinyin.toPinyin(this, "")
}

View File

@ -1,13 +1,12 @@
package de.mm20.launcher2.search.data package de.mm20.launcher2.search.data
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.romanize
import de.mm20.launcher2.ktx.tryStartActivity import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.IconSettings.LegacyIconBackground import de.mm20.launcher2.preferences.Settings.IconSettings.LegacyIconBackground
import de.mm20.launcher2.search.R import de.mm20.launcher2.search.R
import java.text.Collator import java.text.Collator
@ -26,16 +25,26 @@ abstract class Searchable : Comparable<Searchable> {
return if (context.tryStartActivity(intent, options)) { return if (context.tryStartActivity(intent, options)) {
true true
} else { } else {
Toast.makeText(context, context.getString(R.string.error_activity_not_found, label), Toast.LENGTH_SHORT).show() Toast.makeText(
context,
context.getString(R.string.error_activity_not_found, label),
Toast.LENGTH_SHORT
).show()
false false
} }
} }
open suspend fun loadIcon(context: Context, size: Int, legacyIconBackground: LegacyIconBackground): LauncherIcon? = null open suspend fun loadIcon(
context: Context,
size: Int,
legacyIconBackground: LegacyIconBackground
): LauncherIcon? = null
abstract fun getPlaceholderIcon(context: Context): LauncherIcon abstract fun getPlaceholderIcon(context: Context): LauncherIcon
override fun compareTo(other: Searchable): Int { override fun compareTo(other: Searchable): Int {
return Collator.getInstance().apply { strength = Collator.SECONDARY }.compare(label, other.label) return Collator.getInstance().apply { strength = Collator.SECONDARY }
.compare(label.romanize(), other.label.romanize())
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {