diff --git a/app/src/main/java/eu/kanade/data/history/HistoryMapper.kt b/app/src/main/java/eu/kanade/data/history/HistoryMapper.kt index 8164c5e0b4..cb96fee001 100644 --- a/app/src/main/java/eu/kanade/data/history/HistoryMapper.kt +++ b/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, + ), ) } diff --git a/app/src/main/java/eu/kanade/domain/history/model/HistoryWithRelations.kt b/app/src/main/java/eu/kanade/domain/history/model/HistoryWithRelations.kt index 2871b80bec..f3662b9148 100644 --- a/app/src/main/java/eu/kanade/domain/history/model/HistoryWithRelations.kt +++ b/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, ) diff --git a/app/src/main/java/eu/kanade/domain/manga/model/MangaCover.kt b/app/src/main/java/eu/kanade/domain/manga/model/MangaCover.kt new file mode 100644 index 0000000000..748926bb6d --- /dev/null +++ b/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, +) diff --git a/app/src/main/java/eu/kanade/presentation/components/MangaCover.kt b/app/src/main/java/eu/kanade/presentation/components/MangaCover.kt index 2d47b9a9c6..cd5cdb60de 100644 --- a/app/src/main/java/eu/kanade/presentation/components/MangaCover.kt +++ b/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, ) { diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt index 8b15227697..27c93c5ca9 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/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 diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/BaseMangaListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/BaseMangaListItem.kt index 49795acaac..509d3cb8ae 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/BaseMangaListItem.kt +++ b/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, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 18fe23057f..65469a634c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt index 494ab32dba..157e77a692 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt +++ b/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, + private val diskCacheLazy: Lazy, + ) : Fetcher.Factory { + + 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, + private val diskCacheLazy: Lazy, + ) : Fetcher.Factory { + + 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" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt index dec62e337c..8a0ce702ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt +++ b/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 { +class MangaKeyer : Keyer { 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 { } } } + +class DomainMangaKeyer : Keyer { + override fun key(data: DomainManga, options: Options): String { + return if (data.hasCustomCover()) { + "${data.id};${data.coverLastModified}" + } else { + "${data.thumbnailUrl};${data.coverLastModified}" + } + } +} + +class MangaCoverKeyer : Keyer { + override fun key(data: MangaCover, options: Options): String { + return if (Injekt.get().getCustomCoverFile(data.mangaId).exists()) { + "${data.mangaId};${data.lastModified}" + } else { + "${data.url};${data.lastModified}" + } + } +} diff --git a/app/src/main/sqldelight/migrations/17.sqm b/app/src/main/sqldelight/migrations/17.sqm new file mode 100644 index 0000000000..d331a64365 --- /dev/null +++ b/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; diff --git a/app/src/main/sqldelight/view/historyView.sq b/app/src/main/sqldelight/view/historyView.sq index a41f0ce5e6..1b0bb02d6c 100644 --- a/app/src/main/sqldelight/view/historyView.sq +++ b/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