Fix cover fetching in compose views (#7315)
Make sure it passed thru the custom fetcher
This commit is contained in:
parent
02eb3cb6b5
commit
1b804e61cb
@ -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,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
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
|
@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,
|
||||||
) {
|
) {
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user