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) },
)
}
}