Răsfoiți Sursa

Fix cover fetching in compose views (#7315)

Make sure it passed thru the custom fetcher
Ivan Iskandar 2 ani în urmă
părinte
comite
1b804e61cb

+ 10 - 3
app/src/main/java/eu/kanade/data/history/HistoryMapper.kt

@@ -2,6 +2,7 @@ package eu.kanade.data.history
 
 import eu.kanade.domain.history.model.History
 import eu.kanade.domain.history.model.HistoryWithRelations
+import eu.kanade.domain.manga.model.MangaCover
 import java.util.Date
 
 val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readAt, readDuration ->
@@ -13,16 +14,22 @@ val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readA
     )
 }
 
-val historyWithRelationsMapper: (Long, Long, Long, String, String?, Float, Date?, Long) -> HistoryWithRelations = {
-        historyId, mangaId, chapterId, title, thumbnailUrl, chapterNumber, readAt, readDuration ->
+val historyWithRelationsMapper: (Long, Long, Long, String, String?, Long, Boolean, Long, Float, Date?, Long) -> HistoryWithRelations = {
+        historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration ->
     HistoryWithRelations(
         id = historyId,
         chapterId = chapterId,
         mangaId = mangaId,
         title = title,
-        thumbnailUrl = thumbnailUrl ?: "",
         chapterNumber = chapterNumber,
         readAt = readAt,
         readDuration = readDuration,
+        coverData = MangaCover(
+            mangaId = mangaId,
+            sourceId = sourceId,
+            isMangaFavorite = isFavorite,
+            url = thumbnailUrl,
+            lastModified = coverLastModified,
+        ),
     )
 }

+ 2 - 1
app/src/main/java/eu/kanade/domain/history/model/HistoryWithRelations.kt

@@ -1,5 +1,6 @@
 package eu.kanade.domain.history.model
 
+import eu.kanade.domain.manga.model.MangaCover
 import java.util.Date
 
 data class HistoryWithRelations(
@@ -7,8 +8,8 @@ data class HistoryWithRelations(
     val chapterId: Long,
     val mangaId: Long,
     val title: String,
-    val thumbnailUrl: String,
     val chapterNumber: Float,
     val readAt: Date?,
     val readDuration: Long,
+    val coverData: MangaCover,
 )

+ 12 - 0
app/src/main/java/eu/kanade/domain/manga/model/MangaCover.kt

@@ -0,0 +1,12 @@
+package eu.kanade.domain.manga.model
+
+/**
+ * Contains the required data for MangaCoverFetcher
+ */
+data class MangaCover(
+    val mangaId: Long,
+    val sourceId: Long,
+    val isMangaFavorite: Boolean,
+    val url: String?,
+    val lastModified: Long,
+)

+ 1 - 1
app/src/main/java/eu/kanade/presentation/components/MangaCover.kt

@@ -21,7 +21,7 @@ enum class MangaCover(private val ratio: Float) {
     @Composable
     operator fun invoke(
         modifier: Modifier = Modifier,
-        data: String?,
+        data: Any?,
         contentDescription: String? = null,
         shape: Shape? = null,
     ) {

+ 1 - 1
app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt

@@ -191,7 +191,7 @@ fun HistoryItem(
             modifier = Modifier
                 .fillMaxHeight()
                 .clickable(onClick = onClickCover),
-            data = history.thumbnailUrl,
+            data = history.coverData,
         )
         Column(
             modifier = Modifier

+ 1 - 1
app/src/main/java/eu/kanade/presentation/manga/components/BaseMangaListItem.kt

@@ -47,7 +47,7 @@ private val defaultCover: @Composable RowScope.(Manga, () -> Unit) -> Unit = { m
             .padding(vertical = 8.dp)
             .clickable(onClick = onClick)
             .fillMaxHeight(),
-        data = manga.thumbnailUrl,
+        data = manga,
     )
 }
 

+ 6 - 0
app/src/main/java/eu/kanade/tachiyomi/App.kt

@@ -25,8 +25,10 @@ import coil.decode.ImageDecoderDecoder
 import coil.disk.DiskCache
 import coil.util.DebugLogger
 import eu.kanade.domain.DomainModule
+import eu.kanade.tachiyomi.data.coil.DomainMangaKeyer
 import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
 import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
+import eu.kanade.tachiyomi.data.coil.MangaKeyer
 import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.data.preference.PreferenceValues
@@ -139,6 +141,10 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
                 }
                 add(TachiyomiImageDecoder.Factory())
                 add(MangaCoverFetcher.Factory(lazy(callFactoryInit), lazy(diskCacheInit)))
+                add(MangaCoverFetcher.DomainMangaFactory(lazy(callFactoryInit), lazy(diskCacheInit)))
+                add(MangaCoverFetcher.MangaCoverFactory(lazy(callFactoryInit), lazy(diskCacheInit)))
+                add(MangaKeyer())
+                add(DomainMangaKeyer())
                 add(MangaCoverKeyer())
             }
             callFactory(callFactoryInit)

+ 49 - 1
app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt

@@ -10,6 +10,7 @@ import coil.fetch.SourceResult
 import coil.network.HttpException
 import coil.request.Options
 import coil.request.Parameters
+import eu.kanade.domain.manga.model.MangaCover
 import eu.kanade.tachiyomi.data.cache.CoverCache
 import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher.Companion.USE_CUSTOM_COVER
 import eu.kanade.tachiyomi.data.database.models.Manga
@@ -30,6 +31,7 @@ import okio.sink
 import uy.kohesive.injekt.injectLazy
 import java.io.File
 import java.net.HttpURLConnection
+import eu.kanade.domain.manga.model.Manga as DomainManga
 
 /**
  * A [Fetcher] that fetches cover image for [Manga] object.
@@ -290,7 +292,7 @@ class MangaCoverFetcher(
                 options = options,
                 coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnail_url) },
                 customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) },
-                diskCacheKeyLazy = lazy { MangaCoverKeyer().key(data, options) },
+                diskCacheKeyLazy = lazy { MangaKeyer().key(data, options) },
                 sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource },
                 callFactoryLazy = callFactoryLazy,
                 diskCacheLazy = diskCacheLazy,
@@ -298,6 +300,52 @@ class MangaCoverFetcher(
         }
     }
 
+    class DomainMangaFactory(
+        private val callFactoryLazy: Lazy<Call.Factory>,
+        private val diskCacheLazy: Lazy<DiskCache>,
+    ) : Fetcher.Factory<DomainManga> {
+
+        private val coverCache: CoverCache by injectLazy()
+        private val sourceManager: SourceManager by injectLazy()
+
+        override fun create(data: DomainManga, options: Options, imageLoader: ImageLoader): Fetcher {
+            return MangaCoverFetcher(
+                url = data.thumbnailUrl,
+                isLibraryManga = data.favorite,
+                options = options,
+                coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnailUrl) },
+                customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) },
+                diskCacheKeyLazy = lazy { DomainMangaKeyer().key(data, options) },
+                sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource },
+                callFactoryLazy = callFactoryLazy,
+                diskCacheLazy = diskCacheLazy,
+            )
+        }
+    }
+
+    class MangaCoverFactory(
+        private val callFactoryLazy: Lazy<Call.Factory>,
+        private val diskCacheLazy: Lazy<DiskCache>,
+    ) : Fetcher.Factory<MangaCover> {
+
+        private val coverCache: CoverCache by injectLazy()
+        private val sourceManager: SourceManager by injectLazy()
+
+        override fun create(data: MangaCover, options: Options, imageLoader: ImageLoader): Fetcher {
+            return MangaCoverFetcher(
+                url = data.url,
+                isLibraryManga = data.isMangaFavorite,
+                options = options,
+                coverFileLazy = lazy { coverCache.getCoverFile(data.url) },
+                customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.mangaId) },
+                diskCacheKeyLazy = lazy { MangaCoverKeyer().key(data, options) },
+                sourceLazy = lazy { sourceManager.get(data.sourceId) as? HttpSource },
+                callFactoryLazy = callFactoryLazy,
+                diskCacheLazy = diskCacheLazy,
+            )
+        }
+    }
+
     companion object {
         const val USE_CUSTOM_COVER = "use_custom_cover"
 

+ 27 - 1
app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt

@@ -2,10 +2,16 @@ package eu.kanade.tachiyomi.data.coil
 
 import coil.key.Keyer
 import coil.request.Options
+import eu.kanade.domain.manga.model.MangaCover
+import eu.kanade.domain.manga.model.hasCustomCover
+import eu.kanade.tachiyomi.data.cache.CoverCache
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.util.hasCustomCover
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import eu.kanade.domain.manga.model.Manga as DomainManga
 
-class MangaCoverKeyer : Keyer<Manga> {
+class MangaKeyer : Keyer<Manga> {
     override fun key(data: Manga, options: Options): String {
         return if (data.hasCustomCover()) {
             "${data.id};${data.cover_last_modified}"
@@ -14,3 +20,23 @@ class MangaCoverKeyer : Keyer<Manga> {
         }
     }
 }
+
+class DomainMangaKeyer : Keyer<DomainManga> {
+    override fun key(data: DomainManga, options: Options): String {
+        return if (data.hasCustomCover()) {
+            "${data.id};${data.coverLastModified}"
+        } else {
+            "${data.thumbnailUrl};${data.coverLastModified}"
+        }
+    }
+}
+
+class MangaCoverKeyer : Keyer<MangaCover> {
+    override fun key(data: MangaCover, options: Options): String {
+        return if (Injekt.get<CoverCache>().getCustomCoverFile(data.mangaId).exists()) {
+            "${data.mangaId};${data.lastModified}"
+        } else {
+            "${data.url};${data.lastModified}"
+        }
+    }
+}

+ 29 - 0
app/src/main/sqldelight/migrations/17.sqm

@@ -0,0 +1,29 @@
+DROP VIEW IF EXISTS historyView;
+
+CREATE VIEW historyView AS
+SELECT
+    history._id AS id,
+    mangas._id AS mangaId,
+    chapters._id AS chapterId,
+    mangas.title,
+    mangas.thumbnail_url AS thumbnailUrl,
+    mangas.source,
+    mangas.favorite,
+    mangas.cover_last_modified,
+    chapters.chapter_number AS chapterNumber,
+    history.last_read AS readAt,
+    history.time_read AS readDuration,
+    max_last_read.last_read AS maxReadAt,
+    max_last_read.chapter_id AS maxReadAtChapterId
+FROM mangas
+JOIN chapters
+ON mangas._id = chapters.manga_id
+JOIN history
+ON chapters._id = history.chapter_id
+JOIN (
+    SELECT chapters.manga_id,chapters._id AS chapter_id, MAX(history.last_read) AS last_read
+    FROM chapters JOIN history
+    ON chapters._id = history.chapter_id
+    GROUP BY chapters.manga_id
+) AS max_last_read
+ON chapters.manga_id = max_last_read.manga_id;

+ 9 - 0
app/src/main/sqldelight/view/historyView.sq

@@ -5,6 +5,9 @@ SELECT
     chapters._id AS chapterId,
     mangas.title,
     mangas.thumbnail_url AS thumbnailUrl,
+    mangas.source,
+    mangas.favorite,
+    mangas.cover_last_modified,
     chapters.chapter_number AS chapterNumber,
     history.last_read AS readAt,
     history.time_read AS readDuration,
@@ -37,6 +40,9 @@ mangaId,
 chapterId,
 title,
 thumbnailUrl,
+source,
+favorite,
+cover_last_modified,
 chapterNumber,
 readAt,
 readDuration
@@ -54,6 +60,9 @@ mangaId,
 chapterId,
 title,
 thumbnailUrl,
+source,
+favorite,
+cover_last_modified,
 chapterNumber,
 readAt,
 readDuration