Add support for themed icon packs
This commit is contained in:
parent
ebba36c384
commit
9e56f960e6
@ -51,6 +51,9 @@ interface IconDao {
|
||||
@Query("SELECT * FROM IconPack")
|
||||
suspend fun getInstalledIconPacks(): List<IconPackEntity>
|
||||
|
||||
@Query("SELECT * FROM IconPack WHERE packageName = :packageName LIMIT 1")
|
||||
suspend fun getIconPack(packageName: String): IconPackEntity?
|
||||
|
||||
@Query("SELECT * FROM IconPack")
|
||||
fun getInstalledIconPacksLiveData(): LiveData<List<IconPackEntity>>
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import android.content.res.Resources
|
||||
import android.graphics.drawable.AdaptiveIconDrawable
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import de.mm20.launcher2.icons.transformations.LauncherIconTransformation
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.Instant
|
||||
@ -33,36 +34,59 @@ internal class DynamicCalendarIcon(
|
||||
backgroundLayer = ColorLayer()
|
||||
)
|
||||
|
||||
var icon = if (isThemed) {
|
||||
StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
var icon = when {
|
||||
isThemed && drawable is AdaptiveIconDrawable -> {
|
||||
if (isAtLeastApiLevel(33) && drawable.monochrome != null) {
|
||||
return@withContext StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = drawable.monochrome!!,
|
||||
scale = 1f,
|
||||
),
|
||||
backgroundLayer = ColorLayer()
|
||||
)
|
||||
} else {
|
||||
return@withContext StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = drawable.foreground!!,
|
||||
scale = 1.5f,
|
||||
),
|
||||
backgroundLayer = ColorLayer()
|
||||
)
|
||||
}
|
||||
}
|
||||
isThemed -> {
|
||||
StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = drawable,
|
||||
scale = 0.5f,
|
||||
),
|
||||
backgroundLayer = ColorLayer()
|
||||
)
|
||||
}
|
||||
drawable is AdaptiveIconDrawable -> {
|
||||
return@withContext StaticLauncherIcon(
|
||||
foregroundLayer = drawable.foreground?.let {
|
||||
StaticIconLayer(
|
||||
icon = it,
|
||||
scale = 1.5f,
|
||||
)
|
||||
} ?: TransparentLayer,
|
||||
backgroundLayer = drawable.background?.let {
|
||||
StaticIconLayer(
|
||||
icon = it,
|
||||
scale = 1.5f,
|
||||
)
|
||||
} ?: TransparentLayer,
|
||||
)
|
||||
}
|
||||
else -> StaticLauncherIcon(
|
||||
foregroundLayer = StaticIconLayer(
|
||||
icon = drawable,
|
||||
scale = 0.5f,
|
||||
scale = 1f,
|
||||
),
|
||||
backgroundLayer = ColorLayer()
|
||||
backgroundLayer = TransparentLayer
|
||||
)
|
||||
} else if (drawable is AdaptiveIconDrawable) {
|
||||
return@withContext StaticLauncherIcon(
|
||||
foregroundLayer = drawable.foreground?.let {
|
||||
StaticIconLayer(
|
||||
icon = it,
|
||||
scale = 1.5f,
|
||||
)
|
||||
} ?: TransparentLayer,
|
||||
backgroundLayer = drawable.background?.let {
|
||||
StaticIconLayer(
|
||||
icon = it,
|
||||
scale = 1.5f,
|
||||
)
|
||||
} ?: TransparentLayer,
|
||||
)
|
||||
} else StaticLauncherIcon(
|
||||
foregroundLayer = StaticIconLayer(
|
||||
icon = drawable,
|
||||
scale = 1f,
|
||||
),
|
||||
backgroundLayer = TransparentLayer
|
||||
)
|
||||
}
|
||||
|
||||
for (transformation in transformations) {
|
||||
icon = transformation.transform(icon)
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package de.mm20.launcher2.icons
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ResolveInfo
|
||||
import de.mm20.launcher2.database.entities.IconPackEntity
|
||||
|
||||
data class IconPack(
|
||||
@ -8,7 +10,7 @@ data class IconPack(
|
||||
val version: String,
|
||||
var scale: Float = 1f,
|
||||
val themed: Boolean = false,
|
||||
) {
|
||||
) {
|
||||
constructor(entity: IconPackEntity) : this(
|
||||
name = entity.name,
|
||||
packageName = entity.packageName,
|
||||
@ -17,6 +19,17 @@ data class IconPack(
|
||||
themed = entity.themed,
|
||||
)
|
||||
|
||||
internal constructor(
|
||||
context: Context,
|
||||
resolveInfo: ResolveInfo,
|
||||
themed: Boolean = false
|
||||
): this(
|
||||
name = resolveInfo.loadLabel(context.packageManager).toString(),
|
||||
packageName = resolveInfo.activityInfo.packageName,
|
||||
version = context.packageManager.getPackageInfo(resolveInfo.activityInfo.packageName, 0).versionName,
|
||||
themed = themed,
|
||||
)
|
||||
|
||||
fun toDatabaseEntity(): IconPackEntity {
|
||||
return IconPackEntity(
|
||||
name = name,
|
||||
|
||||
@ -14,6 +14,7 @@ import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.database.AppDatabase
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.ktx.obtainTypedArrayOrNull
|
||||
import de.mm20.launcher2.ktx.randomElementOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -46,13 +47,21 @@ class IconPackManager(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getIconPack(packageName: String): IconPack? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
appDatabase.iconDao().getIconPack(packageName)?.let {
|
||||
IconPack(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateIconPacks() {
|
||||
withContext(Dispatchers.IO) {
|
||||
UpdateIconPacksWorker(context).doWork()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getIcon(iconPack: String, componentName: ComponentName): LauncherIcon? {
|
||||
suspend fun getIcon(iconPack: String, componentName: ComponentName, themed: Boolean = false): LauncherIcon? {
|
||||
val res = try {
|
||||
context.packageManager.getResourcesForApplication(iconPack)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
@ -66,7 +75,7 @@ class IconPackManager(
|
||||
val drawableName = icon.drawable ?: return null
|
||||
|
||||
if (icon.type == "calendar") {
|
||||
return getIconPackCalendarIcon(context, iconPack, drawableName)
|
||||
return getIconPackCalendarIcon(context, iconPack, drawableName, themed)
|
||||
}
|
||||
val resId = res.getIdentifier(drawableName, "drawable", iconPack).takeIf { it != 0 }
|
||||
?: return null
|
||||
@ -75,8 +84,27 @@ class IconPackManager(
|
||||
} catch (e: Resources.NotFoundException) {
|
||||
return null
|
||||
}
|
||||
return when (drawable) {
|
||||
is AdaptiveIconDrawable -> {
|
||||
return when {
|
||||
themed && drawable is AdaptiveIconDrawable -> {
|
||||
if (isAtLeastApiLevel(33) && drawable.monochrome != null) {
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = StaticIconLayer(
|
||||
icon = drawable.monochrome!!,
|
||||
scale = 1f,
|
||||
),
|
||||
backgroundLayer = ColorLayer(),
|
||||
)
|
||||
} else {
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = drawable.foreground,
|
||||
scale = 1.5f,
|
||||
),
|
||||
backgroundLayer = ColorLayer(),
|
||||
)
|
||||
}
|
||||
}
|
||||
drawable is AdaptiveIconDrawable -> {
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = drawable.foreground?.let {
|
||||
StaticIconLayer(
|
||||
@ -237,7 +265,8 @@ class IconPackManager(
|
||||
private fun getIconPackCalendarIcon(
|
||||
context: Context,
|
||||
iconPack: String,
|
||||
baseIconName: String
|
||||
baseIconName: String,
|
||||
themed: Boolean,
|
||||
): DynamicCalendarIcon? {
|
||||
val resources = try {
|
||||
context.packageManager.getResourcesForApplication(iconPack)
|
||||
@ -252,7 +281,8 @@ class IconPackManager(
|
||||
}.toIntArray()
|
||||
return DynamicCalendarIcon(
|
||||
resources = resources,
|
||||
resourceIds = drawableIds
|
||||
resourceIds = drawableIds,
|
||||
isThemed = themed,
|
||||
)
|
||||
}
|
||||
|
||||
@ -417,23 +447,16 @@ class IconPackManager(
|
||||
class UpdateIconPacksWorker(val context: Context) {
|
||||
|
||||
fun doWork() {
|
||||
val packs = loadInstalledPacks(context).map { it.activityInfo.packageName }
|
||||
val packs = loadInstalledPacks(context)
|
||||
val grayscaleProviders = loadInstalledGreyscaleProviders(context)
|
||||
val iconDao = AppDatabase.getInstance(context).iconDao()
|
||||
iconDao.uninstallIconPacksExcept(
|
||||
packs.union(grayscaleProviders).toList()
|
||||
packs.map { it.packageName }.union(grayscaleProviders).toList()
|
||||
)
|
||||
|
||||
for (pack in packs) {
|
||||
try {
|
||||
val packInfo = context.packageManager.getPackageInfo(pack, 0)
|
||||
val iconPack = IconPack(
|
||||
name = packInfo.applicationInfo.loadLabel(context.packageManager).toString(),
|
||||
packageName = pack,
|
||||
version = packInfo.versionName
|
||||
)
|
||||
//if (iconDao.isInstalled(iconPack)) continue
|
||||
installIconPack(iconPack)
|
||||
installIconPack(pack)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
continue
|
||||
}
|
||||
@ -455,21 +478,19 @@ class UpdateIconPacksWorker(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadInstalledPacks(context: Context): List<ResolveInfo> {
|
||||
val packs = mutableListOf<ResolveInfo>()
|
||||
private fun loadInstalledPacks(context: Context): List<IconPack> {
|
||||
val packs = mutableListOf<IconPack>()
|
||||
val pm = context.packageManager
|
||||
var intent = Intent("org.adw.ActivityStarter.THEMES")
|
||||
var intent = Intent("app.lawnchair.icons.THEMED_ICON")
|
||||
val themedPacks = pm.queryIntentActivities(intent, 0)
|
||||
packs.addAll(themedPacks.map { IconPack(context, it, true) })
|
||||
intent = Intent("org.adw.ActivityStarter.THEMES")
|
||||
val adwPacks = pm.queryIntentActivities(intent, 0)
|
||||
packs.addAll(adwPacks)
|
||||
packs.addAll(adwPacks.map { IconPack(context, it, false) })
|
||||
intent = Intent("com.novalauncher.THEME")
|
||||
val novaPacks = pm.queryIntentActivities(intent, 0)
|
||||
novaPacks.forEach {
|
||||
if (packs.none { p -> p.activityInfo.packageName == it.activityInfo.packageName }) packs.add(
|
||||
it
|
||||
)
|
||||
}
|
||||
packs.sortWith(ResolveInfo.DisplayNameComparator(pm))
|
||||
return packs
|
||||
packs.addAll(novaPacks.map { IconPack(context, it, false) })
|
||||
return packs.distinctBy { it.packageName }
|
||||
}
|
||||
|
||||
private fun installIconPack(iconPack: IconPack) {
|
||||
|
||||
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Color
|
||||
import android.util.Log
|
||||
import android.util.LruCache
|
||||
import de.mm20.launcher2.data.customattrs.AdaptifiedLegacyIcon
|
||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||
@ -94,13 +95,18 @@ class IconRepository(
|
||||
}
|
||||
|
||||
if (settings.iconPack.isNotBlank()) {
|
||||
providers.add(
|
||||
IconPackIconProvider(
|
||||
context,
|
||||
settings.iconPack,
|
||||
iconPackManager
|
||||
val pack = iconPackManager.getIconPack(settings.iconPack)
|
||||
if (pack != null) {
|
||||
providers.add(
|
||||
IconPackIconProvider(
|
||||
context,
|
||||
pack,
|
||||
iconPackManager
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Log.w("MM20", "Icon pack ${settings.iconPack} not found")
|
||||
}
|
||||
}
|
||||
providers.add(GoogleClockIconProvider(context))
|
||||
providers.add(CalendarIconProvider(context))
|
||||
|
||||
@ -10,17 +10,17 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
class IconPackIconProvider(
|
||||
private val context: Context,
|
||||
private val iconPack: String,
|
||||
private val iconPack: IconPack,
|
||||
private val iconPackManager: IconPackManager,
|
||||
): IconProvider {
|
||||
override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? {
|
||||
if (searchable !is LauncherApp) return null
|
||||
|
||||
val component = ComponentName(searchable.`package`, searchable.activity)
|
||||
return iconPackManager.getIcon(iconPack, component)
|
||||
return iconPackManager.getIcon(iconPack.packageName, component, iconPack.themed)
|
||||
?: iconPackManager.generateIcon(
|
||||
context,
|
||||
iconPack,
|
||||
iconPack.packageName,
|
||||
baseIcon = withContext(Dispatchers.IO) {
|
||||
searchable.launcherActivityInfo.getIcon(context.resources.displayMetrics.densityDpi)
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user