Use imageVectors in badges and fix badge icon colors

This commit is contained in:
MM20 2024-06-16 17:15:57 +02:00
parent 553ab2d9c2
commit a63f434efc
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
11 changed files with 60 additions and 41 deletions

View File

@ -60,6 +60,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.icons.ClockLayer
import de.mm20.launcher2.icons.ClockSublayer
import de.mm20.launcher2.icons.ClockSublayerRole
@ -239,12 +240,11 @@ fun ShapedLauncherIcon(
val _badge = badge()
if (_badge != null) {
Surface(
shadowElevation = 1.dp,
tonalElevation = 1.dp,
modifier = Modifier
.size(size * 0.33f)
.align(Alignment.BottomEnd),
color = MaterialTheme.colorScheme.secondary,
color = MaterialTheme.colorScheme.tertiary,
shape = CircleShape
) {
Box(
@ -255,37 +255,37 @@ fun ShapedLauncherIcon(
val progress by animateFloatAsState(it)
CircularProgressIndicator(
modifier = Modifier.fillMaxSize(0.8f),
progress = progress,
progress = { progress },
strokeWidth = size / 48,
color = MaterialTheme.colorScheme.secondaryContainer
color = MaterialTheme.colorScheme.onTertiary
)
}
val badgeIconRes = _badge.iconRes
val badgeIcon = _badge.icon
val number = _badge.number
if (badgeIconRes != null) {
Image(
if (badgeIcon is BadgeIcon.Vector) {
Icon(
modifier = Modifier
.fillMaxSize()
.padding(size / 48),
painter = painterResource(badgeIconRes),
contentDescription = null
.padding(size / 24),
imageVector = badgeIcon.imageVector,
contentDescription = null,
tint = MaterialTheme.colorScheme.onTertiary,
)
} else if (badgeIcon != null) {
} else if (badgeIcon is BadgeIcon.Drawable) {
Canvas(
modifier = Modifier
.fillMaxSize()
.padding(size / 48)
) {
badgeIcon.setBounds(
badgeIcon.drawable.setBounds(
0,
0,
this.size.width.roundToInt(),
this.size.height.roundToInt()
)
drawIntoCanvas {
badgeIcon.draw(it.nativeCanvas)
badgeIcon.drawable.draw(it.nativeCanvas)
}
}
} else if (number != null && number > 0 && number < 100) {

View File

@ -20,6 +20,7 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.FilterAlt
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.Button
@ -51,6 +52,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.icons.CustomIconWithPreview
import de.mm20.launcher2.icons.IconPack
import de.mm20.launcher2.search.SavableSearchable
@ -106,22 +108,13 @@ fun CustomizeSearchableSheet(
val iconSize = 64.dp
val iconSizePx = iconSize.toPixels()
val icon by remember { viewModel.getIcon(iconSizePx.toInt()) }.collectAsState(null)
val primaryColor = MaterialTheme.colorScheme.onSecondary
val badgeDrawable = remember {
InsetDrawable(
AppCompatResources.getDrawable(context, R.drawable.ic_edit),
8
).also {
it.setTint(primaryColor.toArgb())
}
}
ShapedLauncherIcon(
size = iconSize,
icon = { icon },
badge = {
Badge(
icon = badgeDrawable
icon = BadgeIcon(Icons.Rounded.Edit)
)
},
modifier = Modifier.clickable {

View File

@ -38,7 +38,7 @@ dependencies {
implementation(libs.bundles.kotlin)
implementation(libs.androidx.core)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.compose.materialicons)
implementation(libs.bundles.androidx.lifecycle)
implementation(libs.koin.android)

View File

@ -2,26 +2,36 @@ package de.mm20.launcher2.badges
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.compose.ui.graphics.vector.ImageVector
sealed interface BadgeIcon {
@JvmInline
value class Drawable(val drawable: android.graphics.drawable.Drawable): BadgeIcon
@JvmInline
value class Vector(val imageVector: ImageVector): BadgeIcon
}
fun BadgeIcon(drawable: Drawable): BadgeIcon = BadgeIcon.Drawable(drawable)
fun BadgeIcon(imageVector: ImageVector): BadgeIcon = BadgeIcon.Vector(imageVector)
interface Badge {
val number: Int?
val progress: Float?
val iconRes: Int?
val icon: Drawable?
val icon: BadgeIcon?
}
fun Badge(
number: Int? = null,
progress: Float? = null,
iconRes: Int? = null,
icon: Drawable? = null
): Badge = MutableBadge(number, progress, iconRes, icon)
icon: BadgeIcon? = null
): Badge = MutableBadge(number, progress, icon)
internal data class MutableBadge(
override var number: Int? = null,
override var progress: Float? = null,
override var iconRes: Int? = null,
override var icon: Drawable? = null
override var icon: BadgeIcon? = null
): Badge
fun Collection<Badge>.combine(): Badge? {
@ -30,7 +40,6 @@ fun Collection<Badge>.combine(): Badge? {
var progresses = 0
forEach {
if (it.icon != null && badge.icon == null) badge.icon = it.icon
if (it.iconRes != null && badge.iconRes == null) badge.iconRes = it.iconRes
it.number?.let { a ->
badge.number?.let { b -> badge.number = a + b } ?: run {
badge.number = a

View File

@ -47,7 +47,7 @@ internal class BadgeServiceImpl(
providers += NotificationBadgeProvider()
}
if (it.cloudFiles) {
providers += CloudBadgeProvider()
providers += CloudBadgeProvider(context)
}
if (it.shortcuts) {
providers += AppShortcutBadgeProvider(context)

View File

@ -3,6 +3,7 @@ package de.mm20.launcher2.badges.providers
import android.content.Context
import android.content.pm.PackageManager
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.MutableBadge
import de.mm20.launcher2.graphics.BadgeDrawable
import de.mm20.launcher2.search.AppShortcut
@ -28,7 +29,7 @@ class AppShortcutBadgeProvider(
} catch (e: PackageManager.NameNotFoundException) {
return@withContext
}
val badge = MutableBadge(icon = BadgeDrawable(context, icon))
val badge = MutableBadge(icon = BadgeIcon(BadgeDrawable(context, icon)))
send(badge)
}
} else if (packageName != null) {
@ -40,7 +41,7 @@ class AppShortcutBadgeProvider(
} catch (e: PackageManager.NameNotFoundException) {
return@withContext
}
val badge = MutableBadge(icon = BadgeDrawable(context, icon))
val badge = MutableBadge(icon = BadgeIcon(BadgeDrawable(context, icon)))
send(badge)
}
} else {

View File

@ -1,6 +1,9 @@
package de.mm20.launcher2.badges.providers
import android.content.Context
import androidx.compose.material.icons.Icons
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.MutableBadge
import de.mm20.launcher2.search.File
import de.mm20.launcher2.search.Searchable
@ -8,12 +11,14 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
class CloudBadgeProvider: BadgeProvider {
class CloudBadgeProvider(
private val context: Context
): BadgeProvider {
override fun getBadge(searchable: Searchable): Flow<Badge?> {
if (searchable is File) {
val iconResId = searchable.providerIconRes
if (iconResId != null) {
return flowOf(MutableBadge(iconRes = iconResId))
return flowOf(MutableBadge(icon = BadgeIcon(context.getDrawable(iconResId)!!)))
}
}
return flowOf(null)

View File

@ -1,6 +1,10 @@
package de.mm20.launcher2.badges.providers
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.HourglassBottom
import androidx.compose.material.icons.rounded.VisibilityOff
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.R
import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.search.Searchable
@ -33,7 +37,7 @@ class HiddenItemBadgeProvider(
return hiddenItemKeys.map { keys ->
if (searchable.key in keys) {
Badge(
iconRes = R.drawable.ic_badge_hidden
icon = BadgeIcon(Icons.Rounded.VisibilityOff)
)
} else {
null

View File

@ -2,6 +2,7 @@ package de.mm20.launcher2.badges.providers
import android.content.Context
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.MutableBadge
import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.search.Searchable
@ -16,7 +17,7 @@ class PluginBadgeProvider(private val context: Context): BadgeProvider {
emit(null)
val icon = searchable.getProviderIcon(context)
if (icon != null) {
emit(MutableBadge(icon = icon))
emit(MutableBadge(icon = BadgeIcon(icon)))
}
}
}

View File

@ -1,6 +1,9 @@
package de.mm20.launcher2.badges.providers
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.HourglassBottom
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.MutableBadge
import de.mm20.launcher2.badges.R
import de.mm20.launcher2.search.Application
@ -14,7 +17,7 @@ class SuspendedAppsBadgeProvider : BadgeProvider, KoinComponent {
override fun getBadge(searchable: Searchable): Flow<Badge?> {
return if (searchable is Application && searchable.isSuspended) {
flowOf(MutableBadge(iconRes = R.drawable.ic_badge_suspended))
flowOf(MutableBadge(icon = BadgeIcon(Icons.Rounded.HourglassBottom)))
} else {
flowOf(null)
}

View File

@ -1,6 +1,9 @@
package de.mm20.launcher2.badges.providers
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Work
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.badges.BadgeIcon
import de.mm20.launcher2.badges.MutableBadge
import de.mm20.launcher2.badges.R
import de.mm20.launcher2.search.AppProfile
@ -15,7 +18,7 @@ class WorkProfileBadgeProvider : BadgeProvider {
if (searchable is Application && searchable.profile == AppProfile.Work || searchable is AppShortcut && searchable.profile == AppProfile.Work) {
emit(
MutableBadge(
iconRes = R.drawable.ic_badge_workprofile
icon = BadgeIcon(Icons.Rounded.Work)
)
)
} else {