Add option to pick icons from any icon pack
This commit is contained in:
parent
6cb74e68f6
commit
2e3add0d94
@ -1,6 +1,5 @@
|
||||
package de.mm20.launcher2.customattrs
|
||||
|
||||
import android.graphics.Color
|
||||
import android.util.Log
|
||||
import de.mm20.launcher2.database.entities.CustomAttributeEntity
|
||||
import de.mm20.launcher2.ktx.jsonObjectOf
|
||||
@ -76,7 +75,7 @@ sealed class CustomIcon : CustomAttribute {
|
||||
return when (type) {
|
||||
"custom_icon_pack_icon" -> {
|
||||
CustomIconPackIcon(
|
||||
iconName = payload.getString("icon"),
|
||||
iconComponentName = payload.getString("icon"),
|
||||
iconPackPackage = payload.getString("icon_pack")
|
||||
)
|
||||
}
|
||||
@ -86,6 +85,9 @@ sealed class CustomIcon : CustomAttribute {
|
||||
iconPackPackage = payload.getString("icon_pack")
|
||||
)
|
||||
}
|
||||
"default_icon" -> {
|
||||
UnmodifiedSystemDefaultIcon
|
||||
}
|
||||
"adaptified_legacy_icon" -> {
|
||||
AdaptifiedLegacyIcon(
|
||||
fgScale = payload.getDouble("fg_scale").toFloat(),
|
||||
@ -100,12 +102,12 @@ sealed class CustomIcon : CustomAttribute {
|
||||
|
||||
data class CustomIconPackIcon(
|
||||
val iconPackPackage: String,
|
||||
val iconName: String,
|
||||
val iconComponentName: String,
|
||||
) : CustomIcon() {
|
||||
override fun toDatabaseValue(): String {
|
||||
return jsonObjectOf(
|
||||
"type" to "custom_icon_pack_icon",
|
||||
"icon" to iconName,
|
||||
"icon" to iconComponentName,
|
||||
"icon_pack" to iconPackPackage,
|
||||
).toString()
|
||||
}
|
||||
@ -152,3 +154,15 @@ data class CustomThemedIcon(
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use default icon, ignore any icon pack, themed icon or force adaptive settings.
|
||||
*/
|
||||
object UnmodifiedSystemDefaultIcon: CustomIcon() {
|
||||
override fun toDatabaseValue(): String {
|
||||
return jsonObjectOf(
|
||||
"type" to "default_icon"
|
||||
).toString()
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,9 +13,12 @@ interface IconDao {
|
||||
@Query("SELECT drawable FROM Icons WHERE componentName = :componentName AND iconPack = :iconPack")
|
||||
suspend fun getIconName(componentName: String, iconPack: String): String?
|
||||
|
||||
@Query("SELECT * FROM Icons WHERE componentName = :componentName AND iconPack = :iconPack")
|
||||
@Query("SELECT * FROM Icons WHERE componentName = :componentName AND iconPack = :iconPack AND (type = 'app' OR type = 'calendar') LIMIT 1")
|
||||
suspend fun getIcon(componentName: String, iconPack: String): IconEntity?
|
||||
|
||||
@Query("SELECT * FROM Icons WHERE componentName = :componentName AND (type = 'app' OR type = 'calendar')")
|
||||
suspend fun getIconsFromAllPacks(componentName: String): List<IconEntity>
|
||||
|
||||
@Query("DELETE FROM Icons WHERE iconPack = :iconPack")
|
||||
fun deleteIcons(iconPack: String)
|
||||
|
||||
|
||||
@ -51,14 +51,14 @@ class IconPackManager(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getIcon(iconPack: String, componentName: ComponentName, size: Int): LauncherIcon? {
|
||||
suspend fun getIcon(iconPack: String, componentName: ComponentName): LauncherIcon? {
|
||||
val res = try {
|
||||
context.packageManager.getResourcesForApplication(iconPack)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
Log.e("MM20", "Icon pack package $iconPack not found!")
|
||||
return null
|
||||
}
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
val iconDao = appDatabase.iconDao()
|
||||
val icon = iconDao.getIcon(componentName.flattenToString(), iconPack)
|
||||
?: return null
|
||||
|
||||
@ -185,26 +185,32 @@ class IconPackManager(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getIcons(componentName: ComponentName): List<IconPackIcon> {
|
||||
val iconDao = appDatabase.iconDao()
|
||||
return iconDao.getIconsFromAllPacks(componentName.flattenToString())
|
||||
.map { IconPackIcon(it) }
|
||||
}
|
||||
|
||||
private suspend fun getIconBack(iconPack: String): String? {
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
val iconDao = appDatabase.iconDao()
|
||||
val iconbacks = iconDao.getIconBacks(iconPack)
|
||||
return iconbacks.randomElementOrNull()
|
||||
}
|
||||
|
||||
private suspend fun getIconUpon(iconPack: String): String? {
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
val iconDao = appDatabase.iconDao()
|
||||
val iconupons = iconDao.getIconUpons(iconPack)
|
||||
return iconupons.randomElementOrNull()
|
||||
}
|
||||
|
||||
private suspend fun getIconMask(iconPack: String): String? {
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
val iconDao = appDatabase.iconDao()
|
||||
val iconmasks = iconDao.getIconMasks(iconPack)
|
||||
return iconmasks.randomElementOrNull()
|
||||
}
|
||||
|
||||
private suspend fun getPackScale(iconPack: String): Float {
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
val iconDao = appDatabase.iconDao()
|
||||
return iconDao.getScale(iconPack) ?: 1f
|
||||
}
|
||||
|
||||
|
||||
@ -6,13 +6,12 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Color
|
||||
import android.util.LruCache
|
||||
import de.mm20.launcher2.customattrs.AdaptifiedLegacyIcon
|
||||
import de.mm20.launcher2.customattrs.CustomAttributesRepository
|
||||
import de.mm20.launcher2.customattrs.CustomIcon
|
||||
import de.mm20.launcher2.customattrs.*
|
||||
import de.mm20.launcher2.icons.providers.*
|
||||
import de.mm20.launcher2.icons.transformations.LauncherIconTransformation
|
||||
import de.mm20.launcher2.icons.transformations.LegacyToAdaptiveTransformation
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -101,6 +100,7 @@ class IconRepository(
|
||||
transformations.collectLatest { transformations ->
|
||||
customAttributesRepository.getCustomIcon(searchable).collectLatest { customIcon ->
|
||||
|
||||
val provs = getProviders(customIcon) + providers
|
||||
val transforms = getTransformations(customIcon) ?: transformations
|
||||
|
||||
var icon = cache.get(searchable.key + customIcon.hashCode())
|
||||
@ -112,13 +112,8 @@ class IconRepository(
|
||||
val placeholder = placeholderProvider?.getIcon(searchable, size)
|
||||
placeholder?.let { send(it) }
|
||||
|
||||
for (provider in providers) {
|
||||
val ic = provider.getIcon(searchable, size)
|
||||
if (ic != null) {
|
||||
icon = ic
|
||||
break
|
||||
}
|
||||
}
|
||||
icon = getFirstIcon(searchable, size, provs)
|
||||
|
||||
if (icon != null) {
|
||||
icon = applyTransformations(icon, transforms)
|
||||
|
||||
@ -130,6 +125,23 @@ class IconRepository(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProviders(customIcon: CustomIcon?): List<IconProvider> {
|
||||
if (customIcon is UnmodifiedSystemDefaultIcon) {
|
||||
return listOf(
|
||||
SystemIconProvider(context)
|
||||
)
|
||||
}
|
||||
if (customIcon is CustomIconPackIcon) {
|
||||
return listOf(
|
||||
CustomIconPackIconProvider(
|
||||
customIcon,
|
||||
iconPackManager
|
||||
)
|
||||
)
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun getTransformations(customIcon: CustomIcon?): List<LauncherIconTransformation>? {
|
||||
customIcon ?: return null
|
||||
if (customIcon is AdaptifiedLegacyIcon) {
|
||||
@ -140,6 +152,9 @@ class IconRepository(
|
||||
)
|
||||
)
|
||||
}
|
||||
if (customIcon is UnmodifiedSystemDefaultIcon) {
|
||||
return emptyList()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@ -160,13 +175,7 @@ class IconRepository(
|
||||
): List<CustomIconSuggestion> {
|
||||
val suggestions = mutableListOf<CustomIconSuggestion>()
|
||||
|
||||
var rawIcon = iconProviders.first().firstNotNullOfOrNull {
|
||||
it.getIcon(searchable, size)
|
||||
}
|
||||
|
||||
if (rawIcon == null) {
|
||||
rawIcon = placeholderProvider?.getIcon(searchable, size)
|
||||
}
|
||||
var rawIcon = getFirstIcon(searchable, size, iconProviders.first())
|
||||
|
||||
if (rawIcon == null) {
|
||||
return emptyList()
|
||||
@ -183,56 +192,114 @@ class IconRepository(
|
||||
)
|
||||
)
|
||||
|
||||
val customIcons = mutableListOf<CustomIcon>(UnmodifiedSystemDefaultIcon)
|
||||
|
||||
if (rawIcon is StaticLauncherIcon && rawIcon.backgroundLayer is TransparentLayer) {
|
||||
val adaptifyOptions = listOf(
|
||||
// Legacy icons that simply fill the entire canvas
|
||||
// Legacy icons that simply fill the entire canvas
|
||||
customIcons.add(
|
||||
AdaptifiedLegacyIcon(
|
||||
fgScale = 1f,
|
||||
bgColor = 1
|
||||
),
|
||||
// 48x48 with 5px padding used to be the default icon size for icons generated by
|
||||
// the Android Studio asset generator. Upscale these icons to remove that padding.
|
||||
)
|
||||
)
|
||||
// 48x48 with 5px padding used to be the default icon size for icons generated by
|
||||
// the Android Studio asset generator. Upscale these icons to remove that padding.
|
||||
|
||||
customIcons.add(
|
||||
AdaptifiedLegacyIcon(
|
||||
fgScale = 48f / 38f,
|
||||
bgColor = 1
|
||||
),
|
||||
)
|
||||
)
|
||||
customIcons.add(
|
||||
AdaptifiedLegacyIcon(
|
||||
fgScale = 0.7f,
|
||||
bgColor = 0
|
||||
),
|
||||
)
|
||||
)
|
||||
customIcons.add(
|
||||
AdaptifiedLegacyIcon(
|
||||
fgScale = 0.7f,
|
||||
bgColor = Color.WHITE,
|
||||
)
|
||||
)
|
||||
suggestions.addAll(
|
||||
adaptifyOptions.mapNotNull {
|
||||
val transformation =
|
||||
getTransformations(it)?.firstOrNull() ?: return@mapNotNull null
|
||||
CustomIconSuggestion(
|
||||
icon = transformation.transform(rawIcon),
|
||||
data = it,
|
||||
)
|
||||
}
|
||||
suggestions.addAll(
|
||||
customIcons.map {
|
||||
val transformations = getTransformations(it) ?: defaultTransformations
|
||||
val providers = getProviders(it)
|
||||
|
||||
val icon = getFirstIcon(searchable, size, providers) ?: rawIcon
|
||||
|
||||
CustomIconSuggestion(
|
||||
icon = applyTransformations(icon, transformations),
|
||||
data = it,
|
||||
)
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
val providerOptions = mutableListOf<CustomIcon>()
|
||||
|
||||
if (searchable is LauncherApp) {
|
||||
val iconPackIcons = iconPackManager.getIcons(
|
||||
searchable.launcherActivityInfo.componentName
|
||||
)
|
||||
|
||||
providerOptions.addAll(
|
||||
iconPackIcons.mapNotNull {
|
||||
CustomIconPackIcon(
|
||||
iconPackPackage = it.iconPack,
|
||||
iconComponentName = it.componentName?.flattenToString()
|
||||
?: return@mapNotNull null
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
suggestions.addAll(
|
||||
providerOptions.mapNotNull {
|
||||
val providers = getProviders(it)
|
||||
|
||||
val icon = getFirstIcon(searchable, size, providers) ?: return@mapNotNull null
|
||||
|
||||
CustomIconSuggestion(
|
||||
icon = applyTransformations(icon, defaultTransformations),
|
||||
data = it,
|
||||
)
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
return suggestions
|
||||
|
||||
}
|
||||
|
||||
private suspend fun getFirstIcon(
|
||||
searchable: Searchable,
|
||||
size: Int,
|
||||
providers: List<IconProvider>
|
||||
): LauncherIcon? {
|
||||
for (provider in providers) {
|
||||
val icon = provider.getIcon(searchable, size)
|
||||
if (icon != null) {
|
||||
return icon
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private suspend fun applyTransformations(
|
||||
icon: LauncherIcon,
|
||||
transformations: List<LauncherIconTransformation>
|
||||
): LauncherIcon {
|
||||
var icon = icon
|
||||
if (icon is StaticLauncherIcon) {
|
||||
var transformedIcon = icon
|
||||
if (transformedIcon is StaticLauncherIcon) {
|
||||
for (transformation in transformations) {
|
||||
icon = transformation.transform(icon as StaticLauncherIcon)
|
||||
transformedIcon = transformation.transform(transformedIcon as StaticLauncherIcon)
|
||||
}
|
||||
}
|
||||
return icon
|
||||
return transformedIcon
|
||||
}
|
||||
|
||||
fun setCustomIcon(searchable: Searchable, icon: CustomIcon?) {
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package de.mm20.launcher2.icons.providers
|
||||
|
||||
import de.mm20.launcher2.customattrs.CustomIconPackIcon
|
||||
import de.mm20.launcher2.icons.IconPackManager
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
|
||||
class CustomIconPackIconProvider(
|
||||
private val customIcon: CustomIconPackIcon,
|
||||
private val iconPackManager: IconPackManager,
|
||||
) : IconProvider {
|
||||
override suspend fun getIcon(searchable: Searchable, size: Int): LauncherIcon? {
|
||||
if (searchable !is LauncherApp) return null
|
||||
return iconPackManager.getIcon(
|
||||
customIcon.iconPackPackage,
|
||||
searchable.launcherActivityInfo.componentName
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -2,25 +2,11 @@ package de.mm20.launcher2.icons.providers
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.AdaptiveIconDrawable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.util.Log
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import de.mm20.launcher2.database.AppDatabase
|
||||
import de.mm20.launcher2.icons.*
|
||||
import de.mm20.launcher2.ktx.randomElementOrNull
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class IconPackIconProvider(
|
||||
private val context: Context,
|
||||
@ -31,7 +17,7 @@ class IconPackIconProvider(
|
||||
if (searchable !is LauncherApp) return null
|
||||
|
||||
val component = ComponentName(searchable.`package`, searchable.activity)
|
||||
return iconPackManager.getIcon(iconPack, component, size)
|
||||
return iconPackManager.getIcon(iconPack, component)
|
||||
?: iconPackManager.generateIcon(
|
||||
context,
|
||||
iconPack,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user