diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt index 995684017..de399dcb8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt @@ -99,10 +99,8 @@ internal fun BrowseSourceComfortableGridItem( ogUrl = manga.thumbnailUrl, lastModified = manga.coverLastModified, ), + isSelected = isSelected, coverAlpha = when { - // KMK --> - isSelected -> CommonMangaItemDefaults.BrowseSelectedCoverAlpha - // KMK <-- manga.favorite -> CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else -> 1f }, diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt index 85b691951..18d80f426 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt @@ -99,10 +99,8 @@ internal fun BrowseSourceCompactGridItem( ogUrl = manga.thumbnailUrl, lastModified = manga.coverLastModified, ), + isSelected = isSelected, coverAlpha = when { - // KMK --> - isSelected -> CommonMangaItemDefaults.BrowseSelectedCoverAlpha - // KMK <-- manga.favorite -> CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else -> 1f }, diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt index 228ab1203..120bf9503 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt @@ -92,10 +92,8 @@ internal fun BrowseSourceListItem( ogUrl = manga.thumbnailUrl, lastModified = manga.coverLastModified, ), + isSelected = isSelected, coverAlpha = when { - // KMK --> - isSelected -> CommonMangaItemDefaults.BrowseSelectedCoverAlpha - // KMK <-- manga.favorite -> CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else -> 1f }, diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchCardRow.kt b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchCardRow.kt index 4f868ff34..14f8f887b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchCardRow.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchCardRow.kt @@ -78,10 +78,8 @@ internal fun MangaItem( coverBadgeStart = { InLibraryBadge(enabled = isFavorite) }, + isSelected = isSelected, coverAlpha = when { - // KMK --> - isSelected -> CommonMangaItemDefaults.BrowseSelectedCoverAlpha - // KMK <-- isFavorite -> CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else -> 1f }, diff --git a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt index 46c950635..bb0c5f944 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt @@ -33,25 +33,24 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import eu.kanade.presentation.manga.components.CoverPlaceholderColor import eu.kanade.presentation.manga.components.MangaCover import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.BadgeGroup import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.selectedBackground +import tachiyomi.domain.manga.model.MangaCover as DomainMangaCover object CommonMangaItemDefaults { val GridHorizontalSpacer = 4.dp val GridVerticalSpacer = 4.dp const val BrowseFavoriteCoverAlpha = 0.34f - - // KMK --> - const val BrowseSelectedCoverAlpha = 0.17f - // KMK <-- } private val ContinueReadingButtonSize = 28.dp @@ -66,7 +65,7 @@ private const val GridSelectedCoverAlpha = 0.76f */ @Composable fun MangaCompactGridItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: DomainMangaCover, onClick: () -> Unit, onLongClick: () -> Unit, isSelected: Boolean = false, @@ -86,8 +85,14 @@ fun MangaCompactGridItem( MangaCover.Book( modifier = Modifier .fillMaxWidth() - .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), + .background( + color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) } + ?: MaterialTheme.colorScheme.surface + ), + alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha, data = coverData, + tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second + ?: MaterialTheme.colorScheme.onSurface.toArgb(), ) }, badgesStart = coverBadgeStart, @@ -167,7 +172,7 @@ private fun BoxScope.CoverTextOverlay( */ @Composable fun MangaComfortableGridItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: DomainMangaCover, title: String, onClick: () -> Unit, onLongClick: () -> Unit, @@ -189,8 +194,14 @@ fun MangaComfortableGridItem( MangaCover.Book( modifier = Modifier .fillMaxWidth() - .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), + .background( + color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) } + ?: MaterialTheme.colorScheme.surface + ), + alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha, data = coverData, + tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second + ?: MaterialTheme.colorScheme.onSurface.toArgb(), ) }, badgesStart = coverBadgeStart, @@ -313,14 +324,14 @@ private fun GridItemSelectable( private fun Modifier.selectedOutline( isSelected: Boolean, color: Color, -) = this then drawBehind { if (isSelected) drawRect(color = color) } +) = this.drawBehind { if (isSelected) drawRect(color = color) } /** * Layout of list item. */ @Composable fun MangaListItem( - coverData: tachiyomi.domain.manga.model.MangaCover, + coverData: DomainMangaCover, title: String, onClick: () -> Unit, onLongClick: () -> Unit, @@ -343,8 +354,14 @@ fun MangaListItem( MangaCover.Square( modifier = Modifier .fillMaxHeight() - .alpha(coverAlpha), + .background( + color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) } + ?: MaterialTheme.colorScheme.surface + ), + alpha = coverAlpha, data = coverData, + tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second + ?: MaterialTheme.colorScheme.onSurface.toArgb(), ) Text( text = title, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCover.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCover.kt index 4fb1cf87b..fbd1f1a04 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCover.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCover.kt @@ -1,19 +1,28 @@ package eu.kanade.presentation.manga.components +import androidx.annotation.ColorInt +import androidx.compose.animation.graphics.res.animatedVectorResource +import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter +import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.aspectRatio import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.semantics.Role import coil3.compose.AsyncImage import eu.kanade.presentation.util.rememberResourceBitmapPainter import eu.kanade.tachiyomi.R +import kotlinx.coroutines.delay enum class MangaCover(val ratio: Float) { Square(1f / 1f), @@ -27,15 +36,36 @@ enum class MangaCover(val ratio: Float) { contentDescription: String = "", shape: Shape = MaterialTheme.shapes.extraSmall, onClick: (() -> Unit)? = null, + @ColorInt tint: Int = CoverPlaceholderColor, + alpha: Float = 1f, ) { + val animatedImageVector = AnimatedImageVector.animatedVectorResource(R.drawable.anim_waiting) + var atEnd by remember { mutableStateOf(false) } + + suspend fun runAnimation() { + while (true) { + delay(LoadingAnimatedDuration) + atEnd = !atEnd + } + } + + LaunchedEffect(animatedImageVector) { + runAnimation() + } + + var succeed by remember { mutableStateOf(false) } + AsyncImage( model = data, - placeholder = ColorPainter(CoverPlaceholderColor), - error = rememberResourceBitmapPainter(id = R.drawable.cover_error), + placeholder = rememberAnimatedVectorPainter(animatedImageVector = animatedImageVector, atEnd = atEnd), + error = rememberResourceBitmapPainter(id = R.drawable.cover_error, tint), + fallback = rememberResourceBitmapPainter(id = R.drawable.cover_error, tint), + onSuccess = { succeed = true }, contentDescription = contentDescription, modifier = modifier .aspectRatio(ratio) .clip(shape) + .alpha(if (succeed) alpha else 1f) .then( if (onClick != null) { Modifier.clickable( @@ -51,4 +81,6 @@ enum class MangaCover(val ratio: Float) { } } -private val CoverPlaceholderColor = Color(0x1F888888) +@ColorInt +internal val CoverPlaceholderColor = 0x7F888888 +const val LoadingAnimatedDuration = 600L diff --git a/app/src/main/java/eu/kanade/presentation/util/Resources.kt b/app/src/main/java/eu/kanade/presentation/util/Resources.kt index 5b7bc9948..e9e9cf1c2 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Resources.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Resources.kt @@ -1,6 +1,7 @@ package eu.kanade.presentation.util import android.content.res.Resources +import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -19,11 +20,12 @@ import androidx.core.graphics.drawable.toBitmap * @return the bitmap associated with the resource */ @Composable -fun rememberResourceBitmapPainter(@DrawableRes id: Int): BitmapPainter { +fun rememberResourceBitmapPainter(@DrawableRes id: Int, @ColorInt tint: Int? = null): BitmapPainter { val context = LocalContext.current return remember(id) { val drawable = ContextCompat.getDrawable(context, id) ?: throw Resources.NotFoundException() + tint?.let { drawable.setTint(it) } BitmapPainter(drawable.toBitmap().asImageBitmap()) } } diff --git a/app/src/main/res/drawable/anim_waiting.xml b/app/src/main/res/drawable/anim_waiting.xml new file mode 100644 index 000000000..9e3c740a9 --- /dev/null +++ b/app/src/main/res/drawable/anim_waiting.xml @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/cover_error.xml b/app/src/main/res/drawable/cover_error.xml index 98ca1458d..547a23425 100644 --- a/app/src/main/res/drawable/cover_error.xml +++ b/app/src/main/res/drawable/cover_error.xml @@ -1,5 +1,4 @@ - diff --git a/presentation-core/src/main/res/values/colors.xml b/presentation-core/src/main/res/values/colors.xml index 192790978..75ba59f6a 100644 --- a/presentation-core/src/main/res/values/colors.xml +++ b/presentation-core/src/main/res/values/colors.xml @@ -2,7 +2,8 @@ #EAEDE3 - #1F888888 + #2F888888 + #888888 #BA1B1B #FFDAD4 diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt index 076d25d74..1a88af2b1 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt @@ -2,10 +2,12 @@ package tachiyomi.presentation.widget.components import android.graphics.Bitmap import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.glance.GlanceModifier import androidx.glance.Image import androidx.glance.ImageProvider +import androidx.glance.background import androidx.glance.layout.Box import androidx.glance.layout.ContentScale import androidx.glance.layout.fillMaxSize @@ -20,10 +22,12 @@ val CoverHeight = 87.dp fun UpdatesMangaCover( cover: Bitmap?, modifier: GlanceModifier = GlanceModifier, + color: Color? = null, ) { Box( modifier = modifier .size(width = CoverWidth, height = CoverHeight) + .background(color ?: Color.Unspecified) .appWidgetInnerRadius(), ) { if (cover != null) { diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt index e90e07983..23febec4a 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -3,6 +3,7 @@ package tachiyomi.presentation.widget.components import android.content.Intent import android.graphics.Bitmap import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.glance.GlanceModifier @@ -23,6 +24,7 @@ import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider import kotlinx.collections.immutable.ImmutableList import tachiyomi.core.common.Constants +import tachiyomi.domain.manga.model.MangaCover import tachiyomi.i18n.MR import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.widget.util.calculateRowAndColumnCount @@ -86,6 +88,7 @@ fun UpdatesWidget( UpdatesMangaCover( cover = cover, modifier = GlanceModifier.clickable(actionStartActivity(intent)), + color = MangaCover.coverColorMap[mangaId]?.first?.let { Color(it) }, ) } }