Implement custom legacy to adaptive icon transformations

This commit is contained in:
MM20 2022-07-24 20:47:10 +02:00
parent 5bd86e6f95
commit bb211d4d6a
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
12 changed files with 85 additions and 28 deletions

View File

@ -117,6 +117,7 @@ dependencies {
implementation(project(":contacts"))
implementation(project(":crashreporter"))
implementation(project(":currencies"))
implementation(project(":customattrs"))
implementation(project(":favorites"))
implementation(project(":files"))
implementation(project(":g-services"))

View File

@ -12,6 +12,7 @@ import de.mm20.launcher2.badges.badgesModule
import de.mm20.launcher2.calculator.calculatorModule
import de.mm20.launcher2.calendar.calendarModule
import de.mm20.launcher2.contacts.contactsModule
import de.mm20.launcher2.customattrs.customAttrsModule
import de.mm20.launcher2.debug.Debug
import de.mm20.launcher2.favorites.favoritesModule
import de.mm20.launcher2.files.filesModule
@ -57,6 +58,7 @@ class LauncherApplication : Application(), CoroutineScope, ImageLoaderFactory {
badgesModule,
calendarModule,
contactsModule,
customAttrsModule,
databaseModule,
favoritesModule,
filesModule,

View File

@ -10,7 +10,8 @@ sealed interface CustomAttribute {
fun toDatabaseEntity(key: String): CustomAttributeEntity
companion object {
internal fun fromDatabaseEntity(entity: CustomAttributeEntity): CustomAttribute? {
internal fun fromDatabaseEntity(entity: CustomAttributeEntity?): CustomAttribute? {
if (entity == null) return null
return when (entity.type) {
CustomAttributeType.Label.value -> CustomLabel(
label = entity.value

View File

@ -1,8 +1,22 @@
package de.mm20.launcher2.customattrs
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.search.data.Searchable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
interface CustomAttributesRepository {
fun getCustomAttributes(searchable: Searchable, type: CustomAttributeType? = null): Flow<List<CustomAttribute>>
fun getCustomIcon(searchable: Searchable): Flow<CustomIcon?>
}
internal class CustomAttributesRepositoryImpl(
private val appDatabase: AppDatabase,
) : CustomAttributesRepository {
override fun getCustomIcon(searchable: Searchable): Flow<CustomIcon?> {
val dao = appDatabase.customAttrsDao()
return dao.getCustomIcon(searchable.key)
.map {
CustomAttribute.fromDatabaseEntity(it) as? CustomIcon
}
}
}

View File

@ -3,5 +3,5 @@ package de.mm20.launcher2.customattrs
import org.koin.dsl.module
val customAttrsModule = module {
single<CustomAttributesRepository> { CustomAttributesRepositoryImpl(get()) }
}

View File

@ -28,6 +28,7 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun widgetDao(): WidgetDao
abstract fun currencyDao(): CurrencyDao
abstract fun backupDao(): BackupRestoreDao
abstract fun customAttrsDao(): CustomAttrsDao
companion object {
private var _instance: AppDatabase? = null

View File

@ -0,0 +1,12 @@
package de.mm20.launcher2.database
import androidx.room.Dao
import androidx.room.Query
import de.mm20.launcher2.database.entities.CustomAttributeEntity
import kotlinx.coroutines.flow.Flow
@Dao
interface CustomAttrsDao {
@Query("SELECT * FROM CustomAttributes WHERE type = 'icon' AND key = :key LIMIT 1")
fun getCustomIcon(key: String) : Flow<CustomAttributeEntity?>
}

View File

@ -53,5 +53,6 @@ dependencies {
implementation(project(":search"))
implementation(project(":applications"))
implementation(project(":crashreporter"))
implementation(project(":customattrs"))
}

View File

@ -5,6 +5,9 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
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.icons.providers.*
import de.mm20.launcher2.icons.transformations.LauncherIconTransformation
import de.mm20.launcher2.icons.transformations.LegacyToAdaptiveTransformation
@ -19,7 +22,8 @@ import kotlinx.coroutines.launch
class IconRepository(
val context: Context,
private val iconPackManager: IconPackManager,
private val dataStore: LauncherDataStore
private val dataStore: LauncherDataStore,
private val customAttributesRepository: CustomAttributesRepository,
) {
private val appReceiver = object : BroadcastReceiver() {
@ -93,36 +97,54 @@ class IconRepository(
fun getIcon(searchable: Searchable, size: Int): Flow<LauncherIcon> = channelFlow {
iconProviders.collectLatest { providers ->
transformations.collectLatest { transformations ->
var icon = cache.get(searchable.key)
if (icon != null) {
send(icon)
return@collectLatest
}
customAttributesRepository.getCustomIcon(searchable).collectLatest { customIcon ->
val placeholder = placeholderProvider?.getIcon(searchable, size)
placeholder?.let { send(it) }
val transforms = getTransformations(customIcon) ?: transformations
for (provider in providers) {
val ic = provider.getIcon(searchable, size)
if (ic != null) {
icon = ic
break
var icon = cache.get(searchable.key + customIcon.hashCode())
if (icon != null) {
send(icon)
return@collectLatest
}
}
if (icon != null) {
if (icon is StaticLauncherIcon) {
for (transformation in transformations) {
icon = transformation.transform(icon as StaticLauncherIcon)
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
}
}
if (icon != null) {
if (icon is StaticLauncherIcon) {
for (transformation in transforms) {
icon = transformation.transform(icon as StaticLauncherIcon)
}
}
cache.put(searchable.key, icon)
send(icon)
cache.put(searchable.key + customIcon.hashCode(), icon)
send(icon)
}
}
}
}
}
private fun getTransformations(customIcon: CustomIcon?): List<LauncherIconTransformation>? {
customIcon ?: return null
if (customIcon is AdaptifiedLegacyIcon) {
return listOf(
LegacyToAdaptiveTransformation(
foregroundScale = customIcon.fgScale,
backgroundColor = customIcon.bgColor
)
)
}
return null
}
fun requestIconPackListUpdate() {
scope.launch {

View File

@ -5,5 +5,5 @@ import org.koin.dsl.module
val iconsModule = module {
single { IconPackManager(androidContext()) }
single { IconRepository(androidContext(), get(), get()) }
single { IconRepository(androidContext(), get(), get(), get()) }
}

View File

@ -7,13 +7,16 @@ import de.mm20.launcher2.icons.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
internal class LegacyToAdaptiveTransformation: LauncherIconTransformation {
internal class LegacyToAdaptiveTransformation(
private val foregroundScale: Float = 0.7f,
private val backgroundColor: Int = 1,
): LauncherIconTransformation {
override suspend fun transform(icon: StaticLauncherIcon): StaticLauncherIcon {
if (icon.backgroundLayer !is TransparentLayer) return icon
val bgColor = extractColor(icon.foregroundLayer)
val bgColor = if (backgroundColor == 1) extractColor(icon.foregroundLayer) else backgroundColor
return StaticLauncherIcon(
foregroundLayer = scale(icon.foregroundLayer, 0.7f),
foregroundLayer = scale(icon.foregroundLayer, foregroundScale),
backgroundLayer = ColorLayer(bgColor)
)
}

View File

@ -60,7 +60,7 @@ dependencyResolutionManagement {
listOf("kotlin.stdlib", "kotlinx.coroutines.core", "kotlinx.coroutines.android")
)
version("androidx.compose.compiler", "1.2.0")
version("androidx.compose.compiler", "1.3.0-beta01")
alias("androidx.compose.runtime")
.to("androidx.compose.runtime", "runtime")
.version("1.2.0-rc03")