Fix cover fetching in compose views (#7315)

Make sure it passed thru the custom fetcher
This commit is contained in:
Ivan Iskandar 2022-06-18 09:21:29 +07:00 committed by GitHub
parent 02eb3cb6b5
commit 1b804e61cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 147 additions and 9 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@ import coil.fetch.SourceResult
import coil.network.HttpException import coil.network.HttpException
import coil.request.Options import coil.request.Options
import coil.request.Parameters import coil.request.Parameters
import eu.kanade.domain.manga.model.MangaCover
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher.Companion.USE_CUSTOM_COVER import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher.Companion.USE_CUSTOM_COVER
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
@ -30,6 +31,7 @@ import okio.sink
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.net.HttpURLConnection import java.net.HttpURLConnection
import eu.kanade.domain.manga.model.Manga as DomainManga
/** /**
* A [Fetcher] that fetches cover image for [Manga] object. * A [Fetcher] that fetches cover image for [Manga] object.
@ -290,7 +292,7 @@ class MangaCoverFetcher(
options = options, options = options,
coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnail_url) }, coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnail_url) },
customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) }, 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 }, sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource },
callFactoryLazy = callFactoryLazy, callFactoryLazy = callFactoryLazy,
diskCacheLazy = diskCacheLazy, 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 { companion object {
const val USE_CUSTOM_COVER = "use_custom_cover" const val USE_CUSTOM_COVER = "use_custom_cover"

View File

@ -2,10 +2,16 @@ package eu.kanade.tachiyomi.data.coil
import coil.key.Keyer import coil.key.Keyer
import coil.request.Options 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.data.database.models.Manga
import eu.kanade.tachiyomi.util.hasCustomCover 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 { override fun key(data: Manga, options: Options): String {
return if (data.hasCustomCover()) { return if (data.hasCustomCover()) {
"${data.id};${data.cover_last_modified}" "${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}"
}
}
}

View File

@ -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;

View File

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