Fix cover fetching in compose views (#7315)
Make sure it passed thru the custom fetcher
This commit is contained in:
parent
02eb3cb6b5
commit
1b804e61cb
11 changed files with 147 additions and 9 deletions
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
app/src/main/java/eu/kanade/domain/manga/model/MangaCover.kt
Normal file
12
app/src/main/java/eu/kanade/domain/manga/model/MangaCover.kt
Normal 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,
|
||||
)
|
|
@ -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,
|
||||
) {
|
||||
|
|
|
@ -191,7 +191,7 @@ fun HistoryItem(
|
|||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.clickable(onClick = onClickCover),
|
||||
data = history.thumbnailUrl,
|
||||
data = history.coverData,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
app/src/main/sqldelight/migrations/17.sqm
Normal file
29
app/src/main/sqldelight/migrations/17.sqm
Normal 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;
|
|
@ -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
|
||||
|
|
Reference in a new issue