Apply themed icon colors in UI layer, not in icon repository
This commit is contained in:
parent
8c6b6c5e91
commit
840c7db690
@ -8,11 +8,12 @@ import androidx.palette.graphics.Palette
|
|||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
open class LauncherIcon(
|
open class LauncherIcon(
|
||||||
foreground: Drawable,
|
foreground: Drawable,
|
||||||
background: Drawable? = null,
|
background: Drawable? = null,
|
||||||
foregroundScale: Float = 1f,
|
foregroundScale: Float = 1f,
|
||||||
backgroundScale: Float = 1f,
|
backgroundScale: Float = 1f,
|
||||||
var autoGenerateBackgroundMode: Int = BACKGROUND_WHITE
|
var autoGenerateBackgroundMode: Int = BACKGROUND_WHITE,
|
||||||
|
val isThemeable: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var foreground = foreground
|
var foreground = foreground
|
||||||
|
|||||||
@ -15,6 +15,7 @@ class ClockDynamicLauncherIcon(
|
|||||||
background: Drawable?,
|
background: Drawable?,
|
||||||
foregroundScale: Float,
|
foregroundScale: Float,
|
||||||
backgroundScale: Float,
|
backgroundScale: Float,
|
||||||
|
isThemeable: Boolean = false,
|
||||||
val hourLayer: Int,
|
val hourLayer: Int,
|
||||||
val minuteLayer: Int,
|
val minuteLayer: Int,
|
||||||
val secondLayer: Int
|
val secondLayer: Int
|
||||||
@ -22,7 +23,8 @@ class ClockDynamicLauncherIcon(
|
|||||||
foreground,
|
foreground,
|
||||||
background,
|
background,
|
||||||
foregroundScale,
|
foregroundScale,
|
||||||
backgroundScale
|
backgroundScale,
|
||||||
|
isThemeable = isThemeable
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,13 +7,14 @@ abstract class DynamicLauncherIcon(
|
|||||||
foreground: Drawable,
|
foreground: Drawable,
|
||||||
background: Drawable?,
|
background: Drawable?,
|
||||||
foregroundScale: Float,
|
foregroundScale: Float,
|
||||||
backgroundScale: Float
|
backgroundScale: Float,
|
||||||
)
|
isThemeable: Boolean = false
|
||||||
: LauncherIcon(
|
) : LauncherIcon(
|
||||||
foreground,
|
foreground,
|
||||||
background,
|
background,
|
||||||
foregroundScale,
|
foregroundScale,
|
||||||
backgroundScale,
|
backgroundScale,
|
||||||
|
isThemeable = isThemeable
|
||||||
) {
|
) {
|
||||||
|
|
||||||
abstract fun update(context: Context)
|
abstract fun update(context: Context)
|
||||||
|
|||||||
@ -4,15 +4,15 @@ import android.content.BroadcastReceiver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.res.Resources
|
|
||||||
import android.util.LruCache
|
import android.util.LruCache
|
||||||
import android.util.TypedValue
|
|
||||||
import de.mm20.launcher2.icons.providers.*
|
import de.mm20.launcher2.icons.providers.*
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.search.data.Searchable
|
import de.mm20.launcher2.search.data.Searchable
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class IconRepository(
|
class IconRepository(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
@ -31,8 +31,6 @@ class IconRepository(
|
|||||||
|
|
||||||
private val cache = LruCache<String, LauncherIcon>(200)
|
private val cache = LruCache<String, LauncherIcon>(200)
|
||||||
|
|
||||||
private val themeColors = MutableStateFlow(ThemeColors())
|
|
||||||
|
|
||||||
private var iconProviders: MutableStateFlow<List<IconProvider>> = MutableStateFlow(listOf())
|
private var iconProviders: MutableStateFlow<List<IconProvider>> = MutableStateFlow(listOf())
|
||||||
private lateinit var placeholderProvider: IconProvider
|
private lateinit var placeholderProvider: IconProvider
|
||||||
|
|
||||||
@ -49,30 +47,34 @@ class IconRepository(
|
|||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
dataStore.data.map { it.icons }.distinctUntilChanged().collectLatest { settings ->
|
dataStore.data.map { it.icons }.distinctUntilChanged().collectLatest { settings ->
|
||||||
themeColors.collectLatest { colors ->
|
val placeholderProvider = if (settings.themedIcons) {
|
||||||
val placeholderProvider = if (settings.themedIcons) {
|
ThemedPlaceholderIconProvider(context)
|
||||||
ThemedPlaceholderIconProvider(context, colors)
|
} else {
|
||||||
} else {
|
PlaceholderIconProvider(context)
|
||||||
PlaceholderIconProvider(context)
|
|
||||||
}
|
|
||||||
val providers = mutableListOf<IconProvider>()
|
|
||||||
|
|
||||||
if (settings.themedIcons) {
|
|
||||||
providers.add(ThemedIconProvider(context, colors))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.iconPack.isNotBlank()) {
|
|
||||||
providers.add(IconPackIconProvider(context, settings.iconPack, settings.legacyIconBg))
|
|
||||||
}
|
|
||||||
providers.add(GoogleClockIconProvider(context))
|
|
||||||
providers.add(CalendarIconProvider(context))
|
|
||||||
providers.add(SystemIconProvider(context, settings.legacyIconBg))
|
|
||||||
providers.add(placeholderProvider)
|
|
||||||
cache.evictAll()
|
|
||||||
|
|
||||||
this@IconRepository.placeholderProvider = placeholderProvider
|
|
||||||
iconProviders.value = providers
|
|
||||||
}
|
}
|
||||||
|
val providers = mutableListOf<IconProvider>()
|
||||||
|
|
||||||
|
if (settings.themedIcons) {
|
||||||
|
providers.add(ThemedIconProvider(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.iconPack.isNotBlank()) {
|
||||||
|
providers.add(
|
||||||
|
IconPackIconProvider(
|
||||||
|
context,
|
||||||
|
settings.iconPack,
|
||||||
|
settings.legacyIconBg
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
providers.add(GoogleClockIconProvider(context))
|
||||||
|
providers.add(CalendarIconProvider(context))
|
||||||
|
providers.add(SystemIconProvider(context, settings.legacyIconBg))
|
||||||
|
providers.add(placeholderProvider)
|
||||||
|
cache.evictAll()
|
||||||
|
|
||||||
|
this@IconRepository.placeholderProvider = placeholderProvider
|
||||||
|
iconProviders.value = providers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,19 +122,4 @@ class IconRepository(
|
|||||||
return iconPackManager.getInstalledIconPacks()
|
return iconPackManager.getInstalledIconPacks()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyTheme(theme: Resources.Theme) {
|
|
||||||
val typedValue = TypedValue()
|
|
||||||
val bgColor = theme.resolveAttribute(R.attr.colorPrimaryContainer, typedValue, true).let {
|
|
||||||
typedValue.data
|
|
||||||
}
|
|
||||||
val fgColor = theme.resolveAttribute(R.attr.colorOnPrimaryContainer, typedValue, true).let {
|
|
||||||
typedValue.data
|
|
||||||
}
|
|
||||||
themeColors.value = ThemeColors(foreground = fgColor, background = bgColor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class ThemeColors(
|
|
||||||
val foreground: Int = 0xFFFFFFFF.toInt(),
|
|
||||||
val background: Int = 0xFF000000.toInt(),
|
|
||||||
)
|
|
||||||
@ -2,6 +2,7 @@ package de.mm20.launcher2.icons
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.AdaptiveIconDrawable
|
import android.graphics.drawable.AdaptiveIconDrawable
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@ -14,13 +15,13 @@ class ThemedCalendarDynamicLauncherIcon(
|
|||||||
foregroundScale: Float,
|
foregroundScale: Float,
|
||||||
val packageName: String,
|
val packageName: String,
|
||||||
val foregroundIds: IntArray,
|
val foregroundIds: IntArray,
|
||||||
val foregroundTint: Int,
|
|
||||||
background: Drawable,
|
background: Drawable,
|
||||||
) : DynamicLauncherIcon(
|
) : DynamicLauncherIcon(
|
||||||
foreground = ColorDrawable(0),
|
foreground = ColorDrawable(0),
|
||||||
background = background,
|
background = background,
|
||||||
foregroundScale = foregroundScale,
|
foregroundScale = foregroundScale,
|
||||||
backgroundScale = 1f,
|
backgroundScale = 1f,
|
||||||
|
isThemeable = true,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var currentDay = 0
|
var currentDay = 0
|
||||||
@ -36,7 +37,6 @@ class ThemedCalendarDynamicLauncherIcon(
|
|||||||
Executors.newSingleThreadExecutor().execute {
|
Executors.newSingleThreadExecutor().execute {
|
||||||
val currentDayDrawable = resources.getDrawableOrNull(foregroundIds[day - 1])
|
val currentDayDrawable = resources.getDrawableOrNull(foregroundIds[day - 1])
|
||||||
?: return@execute
|
?: return@execute
|
||||||
currentDayDrawable.setTint(foregroundTint)
|
|
||||||
foreground = currentDayDrawable
|
foreground = currentDayDrawable
|
||||||
}
|
}
|
||||||
currentDay = day
|
currentDay = day
|
||||||
|
|||||||
@ -3,11 +3,10 @@ package de.mm20.launcher2.icons.providers
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.LayerDrawable
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.util.TypedValue
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
import de.mm20.launcher2.database.AppDatabase
|
import de.mm20.launcher2.database.AppDatabase
|
||||||
@ -18,7 +17,6 @@ import de.mm20.launcher2.search.data.Searchable
|
|||||||
|
|
||||||
internal class ThemedIconProvider(
|
internal class ThemedIconProvider(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val colors: ThemeColors,
|
|
||||||
) : IconProvider {
|
) : IconProvider {
|
||||||
|
|
||||||
override suspend fun getIcon(searchable: Searchable, size: Int): LauncherIcon? {
|
override suspend fun getIcon(searchable: Searchable, size: Int): LauncherIcon? {
|
||||||
@ -49,11 +47,11 @@ internal class ThemedIconProvider(
|
|||||||
private fun getStaticIcon(resources: Resources, resId: Int): LauncherIcon? {
|
private fun getStaticIcon(resources: Resources, resId: Int): LauncherIcon? {
|
||||||
try {
|
try {
|
||||||
val fg = ResourcesCompat.getDrawable(resources, resId, null) ?: return null
|
val fg = ResourcesCompat.getDrawable(resources, resId, null) ?: return null
|
||||||
fg.setTint(colors.foreground)
|
|
||||||
return LauncherIcon(
|
return LauncherIcon(
|
||||||
foreground = fg,
|
foreground = fg,
|
||||||
foregroundScale = 0.5f,
|
foregroundScale = 0.5f,
|
||||||
background = ColorDrawable(colors.background)
|
background = ColorDrawable(Color.WHITE),
|
||||||
|
isThemeable = true
|
||||||
)
|
)
|
||||||
} catch (e: Resources.NotFoundException) {
|
} catch (e: Resources.NotFoundException) {
|
||||||
return null
|
return null
|
||||||
@ -85,15 +83,15 @@ internal class ThemedIconProvider(
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if (drawable != null && minuteIndex != null && hourIndex != null) {
|
if (drawable != null && minuteIndex != null && hourIndex != null) {
|
||||||
drawable.setTint(colors.foreground)
|
|
||||||
return ClockDynamicLauncherIcon(
|
return ClockDynamicLauncherIcon(
|
||||||
foreground = drawable,
|
foreground = drawable,
|
||||||
background = ColorDrawable(colors.background),
|
background = ColorDrawable(Color.WHITE),
|
||||||
foregroundScale = 1.5f,
|
foregroundScale = 1.5f,
|
||||||
backgroundScale = 1f,
|
backgroundScale = 1f,
|
||||||
hourLayer = hourIndex,
|
hourLayer = hourIndex,
|
||||||
minuteLayer = minuteIndex,
|
minuteLayer = minuteIndex,
|
||||||
secondLayer = -1,
|
secondLayer = -1,
|
||||||
|
isThemeable = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Resources.NotFoundException) {
|
} catch (e: Resources.NotFoundException) {
|
||||||
@ -111,13 +109,12 @@ internal class ThemedIconProvider(
|
|||||||
if (array.length() != 31) return null
|
if (array.length() != 31) return null
|
||||||
|
|
||||||
return ThemedCalendarDynamicLauncherIcon(
|
return ThemedCalendarDynamicLauncherIcon(
|
||||||
background = ColorDrawable(colors.background),
|
foregroundScale = 0.5f,
|
||||||
packageName = iconProviderPackage,
|
packageName = iconProviderPackage,
|
||||||
foregroundIds = IntArray(31) {
|
foregroundIds = IntArray(31) {
|
||||||
array.getResourceId(it, 0).takeIf { it != 0 } ?: return null
|
array.getResourceId(it, 0).takeIf { it != 0 } ?: return null
|
||||||
},
|
},
|
||||||
foregroundTint = colors.foreground,
|
background = ColorDrawable(Color.WHITE),
|
||||||
foregroundScale = 0.5f,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
} catch (e: Resources.NotFoundException) {
|
} catch (e: Resources.NotFoundException) {
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
package de.mm20.launcher2.icons.providers
|
package de.mm20.launcher2.icons.providers
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.util.TypedValue
|
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.icons.R
|
|
||||||
import de.mm20.launcher2.icons.ThemeColors
|
|
||||||
import de.mm20.launcher2.search.data.Searchable
|
import de.mm20.launcher2.search.data.Searchable
|
||||||
|
|
||||||
internal class ThemedPlaceholderIconProvider(
|
internal class ThemedPlaceholderIconProvider(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val colors: ThemeColors,
|
|
||||||
) : IconProvider {
|
) : IconProvider {
|
||||||
|
|
||||||
override suspend fun getIcon(searchable: Searchable, size: Int): LauncherIcon {
|
override suspend fun getIcon(searchable: Searchable, size: Int): LauncherIcon {
|
||||||
val icon = searchable.getPlaceholderIcon(context)
|
val icon = searchable.getPlaceholderIcon(context)
|
||||||
|
|
||||||
icon.foreground.setTint(colors.foreground)
|
return LauncherIcon(
|
||||||
icon.background?.setTint(colors.background)
|
foreground = icon.foreground,
|
||||||
return icon
|
foregroundScale = icon.foregroundScale,
|
||||||
|
background = icon.background,
|
||||||
|
backgroundScale = icon.backgroundScale,
|
||||||
|
isThemeable = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -36,9 +36,6 @@ class LauncherActivity : BaseActivity() {
|
|||||||
|
|
||||||
viewModel.setDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
|
viewModel.setDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
|
||||||
val iconRepository: IconRepository by inject()
|
|
||||||
iconRepository.applyTheme(theme)
|
|
||||||
|
|
||||||
binding = ActivityLauncherBinding.inflate(LayoutInflater.from(this))
|
binding = ActivityLauncherBinding.inflate(LayoutInflater.from(this))
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user