From 32170cfc48559c214ac2e155b0a4a0abffc8f942 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sun, 30 Aug 2026 17:04:59 +0200 Subject: [PATCH] show badges in iconless app list close #1982 --- .../de/mm20/launcher2/ui/component/Badge.kt | 97 +++++++++++++++++++ .../ui/component/ShapedLauncherIcon.kt | 66 +------------ .../ui/launcher/search/apps/AppItem.kt | 4 + 3 files changed, 106 insertions(+), 61 deletions(-) create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/component/Badge.kt diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/Badge.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/Badge.kt new file mode 100644 index 000000000..cdb02f053 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/Badge.kt @@ -0,0 +1,97 @@ +package de.mm20.launcher2.ui.component + +import android.icu.text.NumberFormat +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import de.mm20.launcher2.badges.Badge +import de.mm20.launcher2.badges.BadgeIcon +import kotlin.math.roundToInt + +@Composable +fun Badge( + badge: Badge, + modifier: Modifier = Modifier, + size: Dp = 16.dp +) { + Surface( + tonalElevation = 1.dp, + modifier = modifier.size(size), + color = MaterialTheme.colorScheme.secondary, + shape = CircleShape + ) { + Box( + contentAlignment = Alignment.Center + ) { + + badge.progress?.let { + val progress by animateFloatAsState(it) + CircularProgressIndicator( + modifier = Modifier.fillMaxSize(0.8f), + progress = { progress }, + strokeWidth = size / 16, + color = MaterialTheme.colorScheme.onSecondary + ) + } + val badgeIcon = badge.icon + + val number = badge.number + if (badgeIcon is BadgeIcon.Vector) { + Icon( + modifier = Modifier + .fillMaxSize() + .padding(size / 8), + painter = painterResource(badgeIcon.iconRes), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSecondary, + ) + } else if (badgeIcon is BadgeIcon.Drawable) { + Canvas( + modifier = Modifier + .fillMaxSize() + .padding(size / 16) + ) { + badgeIcon.drawable.setBounds( + 0, + 0, + this.size.width.roundToInt(), + this.size.height.roundToInt() + ) + drawIntoCanvas { + badgeIcon.drawable.draw(it.nativeCanvas) + } + } + } else if (number != null && number > 0 && number < 100) { + Text( + NumberFormat.getInstance(Locale.current.platformLocale).format(number), + color = MaterialTheme.colorScheme.onSecondary, + style = MaterialTheme.typography.labelSmall.copy( + fontSize = with(LocalDensity.current) { + size.toSp() * 0.6f + } + ), + ) + } + } + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/ShapedLauncherIcon.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/ShapedLauncherIcon.kt index ba915a17b..0549f5be4 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/ShapedLauncherIcon.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/ShapedLauncherIcon.kt @@ -241,68 +241,12 @@ fun ShapedLauncherIcon( } val _badge = badge() if (_badge != null) { - Surface( - tonalElevation = 1.dp, + Badge( + badge = _badge, modifier = Modifier - .size(size * 0.33f) - .align(Alignment.BottomEnd), - color = MaterialTheme.colorScheme.tertiary, - shape = CircleShape - ) { - Box( - contentAlignment = Alignment.Center - ) { - - _badge.progress?.let { - val progress by animateFloatAsState(it) - CircularProgressIndicator( - modifier = Modifier.fillMaxSize(0.8f), - progress = { progress }, - strokeWidth = size / 48, - color = MaterialTheme.colorScheme.onTertiary - ) - } - val badgeIcon = _badge.icon - - val number = _badge.number - if (badgeIcon is BadgeIcon.Vector) { - Icon( - modifier = Modifier - .fillMaxSize() - .padding(size / 24), - painter = painterResource(badgeIcon.iconRes), - contentDescription = null, - tint = MaterialTheme.colorScheme.onTertiary, - ) - } else if (badgeIcon is BadgeIcon.Drawable) { - Canvas( - modifier = Modifier - .fillMaxSize() - .padding(size / 48) - ) { - badgeIcon.drawable.setBounds( - 0, - 0, - this.size.width.roundToInt(), - this.size.height.roundToInt() - ) - drawIntoCanvas { - badgeIcon.drawable.draw(it.nativeCanvas) - } - } - } else if (number != null && number > 0 && number < 100) { - Text( - NumberFormat.getInstance(Locale.current.platformLocale).format(number), - color = MaterialTheme.colorScheme.secondaryContainer, - style = MaterialTheme.typography.labelSmall.copy( - fontSize = with(LocalDensity.current) { - size.toSp() * 0.2f - } - ), - ) - } - } - } + .align(Alignment.BottomEnd) , + size = size * 0.33f + ) } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt index 03f0c9dcb..08b7c37f4 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt @@ -55,6 +55,7 @@ import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.ktx.sendWithBackgroundPermission import de.mm20.launcher2.search.Application import de.mm20.launcher2.ui.R +import de.mm20.launcher2.ui.component.Badge import de.mm20.launcher2.ui.component.DefaultToolbarAction import de.mm20.launcher2.ui.component.ShapedLauncherIcon import de.mm20.launcher2.ui.component.SubmenuToolbarAction @@ -525,6 +526,9 @@ fun AppItem( this@AnimatedContent, ), ) + if (!LocalGridSettings.current.showListIcons && badge != null) { + Badge(badge = badge!!, size = 16.dp, modifier = Modifier.padding(start = 8.dp)) + } } } }