فهرست منبع

Move `LibraryManga` to domain layer (#8126)

AntsyLich 2 سال پیش
والد
کامیت
ea8383978b
20فایلهای تغییر یافته به همراه218 افزوده شده و 233 حذف شده
  1. 28 25
      app/src/main/java/eu/kanade/data/manga/MangaMapper.kt
  2. 1 1
      app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt
  3. 16 0
      app/src/main/java/eu/kanade/domain/library/model/LibraryManga.kt
  4. 1 1
      app/src/main/java/eu/kanade/domain/manga/interactor/GetLibraryManga.kt
  5. 1 1
      app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt
  6. 1 1
      app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt
  7. 1 1
      app/src/main/java/eu/kanade/presentation/library/LibraryState.kt
  8. 9 8
      app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt
  9. 9 8
      app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt
  10. 2 2
      app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt
  11. 9 8
      app/src/main/java/eu/kanade/presentation/library/components/LibraryCoverOnlyGrid.kt
  12. 2 2
      app/src/main/java/eu/kanade/presentation/library/components/LibraryGridCover.kt
  13. 9 8
      app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt
  14. 1 1
      app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt
  15. 0 35
      app/src/main/java/eu/kanade/tachiyomi/data/database/models/LibraryManga.kt
  16. 68 70
      app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
  17. 4 5
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
  18. 14 14
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt
  19. 32 32
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
  20. 10 10
      app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt

+ 28 - 25
app/src/main/java/eu/kanade/data/manga/MangaMapper.kt

@@ -1,7 +1,7 @@
 package eu.kanade.data.manga
 
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.model.Manga
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.source.model.UpdateStrategy
 
 val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy) -> Manga =
@@ -29,28 +29,31 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
     }
 
 val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long) -> LibraryManga =
-    { _id, source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, unread_count, read_count, category ->
-        LibraryManga().apply {
-            this.id = _id
-            this.source = source
-            this.url = url
-            this.artist = artist
-            this.author = author
-            this.description = description
-            this.genre = genre?.joinToString()
-            this.title = title
-            this.status = status.toInt()
-            this.thumbnail_url = thumbnail_url
-            this.favorite = favorite
-            this.last_update = last_update ?: 0
-            this.update_strategy = update_strategy
-            this.initialized = initialized
-            this.viewer_flags = viewer.toInt()
-            this.chapter_flags = chapter_flags.toInt()
-            this.cover_last_modified = cover_last_modified
-            this.date_added = date_added
-            this.unreadCount = unread_count.toInt()
-            this.readCount = read_count.toInt()
-            this.category = category.toInt()
-        }
+    { _id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, unreadCount, readCount, category ->
+        LibraryManga(
+            manga = mangaMapper(
+                _id,
+                source,
+                url,
+                artist,
+                author,
+                description,
+                genre,
+                title,
+                status,
+                thumbnailUrl,
+                favorite,
+                lastUpdate,
+                nextUpdate,
+                initialized,
+                viewerFlags,
+                chapterFlags,
+                coverLastModified,
+                dateAdded,
+                updateStrategy,
+            ),
+            category = category,
+            unreadCount = unreadCount,
+            readCount = readCount,
+        )
     }

+ 1 - 1
app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt

@@ -3,10 +3,10 @@ package eu.kanade.data.manga
 import eu.kanade.data.DatabaseHandler
 import eu.kanade.data.listOfStringsAdapter
 import eu.kanade.data.updateStrategyAdapter
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.model.Manga
 import eu.kanade.domain.manga.model.MangaUpdate
 import eu.kanade.domain.manga.repository.MangaRepository
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.util.system.logcat
 import eu.kanade.tachiyomi.util.system.toLong
 import kotlinx.coroutines.flow.Flow

+ 16 - 0
app/src/main/java/eu/kanade/domain/library/model/LibraryManga.kt

@@ -0,0 +1,16 @@
+package eu.kanade.domain.library.model
+
+import eu.kanade.domain.manga.model.Manga
+
+data class LibraryManga(
+    val manga: Manga,
+    val category: Long,
+    val unreadCount: Long,
+    val readCount: Long,
+) {
+    val totalChapters
+        get() = readCount + unreadCount
+
+    val hasStarted
+        get() = readCount > 0
+}

+ 1 - 1
app/src/main/java/eu/kanade/domain/manga/interactor/GetLibraryManga.kt

@@ -1,7 +1,7 @@
 package eu.kanade.domain.manga.interactor
 
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.repository.MangaRepository
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import kotlinx.coroutines.flow.Flow
 
 class GetLibraryManga(

+ 1 - 1
app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt

@@ -1,8 +1,8 @@
 package eu.kanade.domain.manga.repository
 
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.model.Manga
 import eu.kanade.domain.manga.model.MangaUpdate
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import kotlinx.coroutines.flow.Flow
 
 interface MangaRepository {

+ 1 - 1
app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt

@@ -55,7 +55,7 @@ fun LibraryScreen(
                         onChangeCategoryClicked = onChangeCategoryClicked,
                         onMarkAsReadClicked = onMarkAsReadClicked,
                         onMarkAsUnreadClicked = onMarkAsUnreadClicked,
-                        onDownloadClicked = onDownloadClicked.takeIf { presenter.selection.none { it.source == LocalSource.ID } },
+                        onDownloadClicked = onDownloadClicked.takeIf { presenter.selection.none { it.manga.source == LocalSource.ID } },
                         onDeleteClicked = onDeleteClicked,
                     )
                 },

+ 1 - 1
app/src/main/java/eu/kanade/presentation/library/LibraryState.kt

@@ -6,7 +6,7 @@ import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import eu.kanade.domain.category.model.Category
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryPresenter
 
 @Stable

+ 9 - 8
app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt

@@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.model.MangaCover
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 
 @Composable
@@ -38,7 +38,7 @@ fun LibraryComfortableGrid(
         ) { libraryItem ->
             LibraryComfortableGridItem(
                 libraryItem,
-                libraryItem.manga in selection,
+                libraryItem.libraryManga in selection,
                 onClick,
                 onLongClick,
             )
@@ -53,26 +53,27 @@ fun LibraryComfortableGridItem(
     onClick: (LibraryManga) -> Unit,
     onLongClick: (LibraryManga) -> Unit,
 ) {
-    val manga = item.manga
+    val libraryManga = item.libraryManga
+    val manga = libraryManga.manga
     LibraryGridItemSelectable(isSelected = isSelected) {
         Column(
             modifier = Modifier
                 .combinedClickable(
                     onClick = {
-                        onClick(manga)
+                        onClick(libraryManga)
                     },
                     onLongClick = {
-                        onLongClick(manga)
+                        onLongClick(libraryManga)
                     },
                 ),
         ) {
             LibraryGridCover(
                 mangaCover = MangaCover(
-                    manga.id!!,
+                    manga.id,
                     manga.source,
                     manga.favorite,
-                    manga.thumbnail_url,
-                    manga.cover_last_modified,
+                    manga.thumbnailUrl,
+                    manga.coverLastModified,
                 ),
                 downloadCount = item.downloadCount,
                 unreadCount = item.unreadCount,

+ 9 - 8
app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt

@@ -22,7 +22,7 @@ import androidx.compose.ui.graphics.Shadow
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 
 @Composable
@@ -47,7 +47,7 @@ fun LibraryCompactGrid(
         ) { libraryItem ->
             LibraryCompactGridItem(
                 item = libraryItem,
-                isSelected = libraryItem.manga in selection,
+                isSelected = libraryItem.libraryManga in selection,
                 onClick = onClick,
                 onLongClick = onLongClick,
             )
@@ -62,24 +62,25 @@ fun LibraryCompactGridItem(
     onClick: (LibraryManga) -> Unit,
     onLongClick: (LibraryManga) -> Unit,
 ) {
-    val manga = item.manga
+    val libraryManga = item.libraryManga
+    val manga = libraryManga.manga
     LibraryGridCover(
         modifier = Modifier
             .selectedOutline(isSelected)
             .combinedClickable(
                 onClick = {
-                    onClick(manga)
+                    onClick(libraryManga)
                 },
                 onLongClick = {
-                    onLongClick(manga)
+                    onLongClick(libraryManga)
                 },
             ),
         mangaCover = eu.kanade.domain.manga.model.MangaCover(
-            manga.id!!,
+            manga.id,
             manga.source,
             manga.favorite,
-            manga.thumbnail_url,
-            manga.cover_last_modified,
+            manga.thumbnailUrl,
+            manga.coverLastModified,
         ),
         downloadCount = item.downloadCount,
         unreadCount = item.unreadCount,

+ 2 - 2
app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt

@@ -19,11 +19,11 @@ import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
 import eu.kanade.core.prefs.PreferenceMutableState
 import eu.kanade.domain.category.model.Category
 import eu.kanade.domain.library.model.LibraryDisplayMode
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.presentation.components.EmptyScreen
 import eu.kanade.presentation.components.SwipeRefreshIndicator
 import eu.kanade.presentation.library.LibraryState
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 import eu.kanade.tachiyomi.widget.EmptyView
 import kotlinx.coroutines.delay
@@ -72,7 +72,7 @@ fun LibraryContent(
 
         val onClickManga = { manga: LibraryManga ->
             if (state.selectionMode.not()) {
-                onMangaClicked(manga.id!!)
+                onMangaClicked(manga.manga.id)
             } else {
                 onToggleSelection(manga)
             }

+ 9 - 8
app/src/main/java/eu/kanade/presentation/library/components/LibraryCoverOnlyGrid.kt

@@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.lazy.grid.items
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 
 @Composable
@@ -30,7 +30,7 @@ fun LibraryCoverOnlyGrid(
         ) { libraryItem ->
             LibraryCoverOnlyGridItem(
                 item = libraryItem,
-                isSelected = libraryItem.manga in selection,
+                isSelected = libraryItem.libraryManga in selection,
                 onClick = onClick,
                 onLongClick = onLongClick,
             )
@@ -45,24 +45,25 @@ fun LibraryCoverOnlyGridItem(
     onClick: (LibraryManga) -> Unit,
     onLongClick: (LibraryManga) -> Unit,
 ) {
-    val manga = item.manga
+    val libraryManga = item.libraryManga
+    val manga = libraryManga.manga
     LibraryGridCover(
         modifier = Modifier
             .selectedOutline(isSelected)
             .combinedClickable(
                 onClick = {
-                    onClick(manga)
+                    onClick(libraryManga)
                 },
                 onLongClick = {
-                    onLongClick(manga)
+                    onLongClick(libraryManga)
                 },
             ),
         mangaCover = eu.kanade.domain.manga.model.MangaCover(
-            manga.id!!,
+            manga.id,
             manga.source,
             manga.favorite,
-            manga.thumbnail_url,
-            manga.cover_last_modified,
+            manga.thumbnailUrl,
+            manga.coverLastModified,
         ),
         downloadCount = item.downloadCount,
         unreadCount = item.unreadCount,

+ 2 - 2
app/src/main/java/eu/kanade/presentation/library/components/LibraryGridCover.kt

@@ -56,8 +56,8 @@ fun MangaGridCover(
 fun LibraryGridCover(
     modifier: Modifier = Modifier,
     mangaCover: eu.kanade.domain.manga.model.MangaCover,
-    downloadCount: Int,
-    unreadCount: Int,
+    downloadCount: Long,
+    unreadCount: Long,
     isLocal: Boolean,
     language: String,
     content: @Composable BoxScope.() -> Unit = {},

+ 9 - 8
app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt

@@ -17,6 +17,7 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.manga.model.MangaCover
 import eu.kanade.presentation.components.Badge
 import eu.kanade.presentation.components.BadgeGroup
@@ -28,7 +29,6 @@ import eu.kanade.presentation.util.horizontalPadding
 import eu.kanade.presentation.util.selectedBackground
 import eu.kanade.presentation.util.verticalPadding
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 
 @Composable
@@ -61,7 +61,7 @@ fun LibraryList(
         ) { libraryItem ->
             LibraryListItem(
                 item = libraryItem,
-                isSelected = libraryItem.manga in selection,
+                isSelected = libraryItem.libraryManga in selection,
                 onClick = onClick,
                 onLongClick = onLongClick,
             )
@@ -76,19 +76,20 @@ fun LibraryListItem(
     onClick: (LibraryManga) -> Unit,
     onLongClick: (LibraryManga) -> Unit,
 ) {
-    val manga = item.manga
+    val libraryManga = item.libraryManga
+    val manga = libraryManga.manga
     MangaListItem(
         modifier = Modifier.selectedBackground(isSelected),
         title = manga.title,
         cover = MangaCover(
-            manga.id!!,
+            manga.id,
             manga.source,
             manga.favorite,
-            manga.thumbnail_url,
-            manga.cover_last_modified,
+            manga.thumbnailUrl,
+            manga.coverLastModified,
         ),
-        onClick = { onClick(manga) },
-        onLongClick = { onLongClick(manga) },
+        onClick = { onClick(libraryManga) },
+        onLongClick = { onLongClick(libraryManga) },
     ) {
         if (item.downloadCount > 0) {
             Badge(

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

@@ -13,7 +13,7 @@ import com.google.accompanist.pager.HorizontalPager
 import com.google.accompanist.pager.PagerState
 import eu.kanade.core.prefs.PreferenceMutableState
 import eu.kanade.domain.library.model.LibraryDisplayMode
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.tachiyomi.ui.library.LibraryItem
 
 @Composable

+ 0 - 35
app/src/main/java/eu/kanade/tachiyomi/data/database/models/LibraryManga.kt

@@ -1,35 +0,0 @@
-package eu.kanade.tachiyomi.data.database.models
-
-class LibraryManga : MangaImpl() {
-
-    var unreadCount: Int = 0
-    var readCount: Int = 0
-
-    val totalChapters
-        get() = readCount + unreadCount
-
-    val hasStarted
-        get() = readCount > 0
-
-    var category: Int = 0
-
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is LibraryManga) return false
-        if (!super.equals(other)) return false
-
-        if (unreadCount != other.unreadCount) return false
-        if (readCount != other.readCount) return false
-        if (category != other.category) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = super.hashCode()
-        result = 31 * result + unreadCount
-        result = 31 * result + readCount
-        result = 31 * result + category
-        return result
-    }
-}

+ 68 - 70
app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt

@@ -14,10 +14,12 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
 import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 import eu.kanade.domain.chapter.model.toDbChapter
 import eu.kanade.domain.download.service.DownloadPreferences
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.library.service.LibraryPreferences
 import eu.kanade.domain.manga.interactor.GetLibraryManga
 import eu.kanade.domain.manga.interactor.GetManga
 import eu.kanade.domain.manga.interactor.UpdateManga
+import eu.kanade.domain.manga.model.Manga
 import eu.kanade.domain.manga.model.toMangaUpdate
 import eu.kanade.domain.track.interactor.GetTracks
 import eu.kanade.domain.track.interactor.InsertTrack
@@ -26,10 +28,7 @@ import eu.kanade.domain.track.model.toDomainTrack
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.cache.CoverCache
 import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
-import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.database.models.toDomainChapter
-import eu.kanade.tachiyomi.data.database.models.toDomainManga
 import eu.kanade.tachiyomi.data.download.DownloadManager
 import eu.kanade.tachiyomi.data.download.DownloadService
 import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
@@ -75,7 +74,6 @@ import java.util.concurrent.CopyOnWriteArrayList
 import java.util.concurrent.atomic.AtomicBoolean
 import java.util.concurrent.atomic.AtomicInteger
 import eu.kanade.domain.chapter.model.Chapter as DomainChapter
-import eu.kanade.domain.manga.model.Manga as DomainManga
 
 /**
  * This class will take care of updating the chapters of the manga from the library. It can be
@@ -261,20 +259,20 @@ class LibraryUpdateService(
      *
      * @param categoryId the ID of the category to update, or -1 if no category specified.
      */
-    fun addMangaToQueue(categoryId: Long) {
+    private fun addMangaToQueue(categoryId: Long) {
         val libraryManga = runBlocking { getLibraryManga.await() }
 
         val listToUpdate = if (categoryId != -1L) {
-            libraryManga.filter { it.category.toLong() == categoryId }
+            libraryManga.filter { it.category == categoryId }
         } else {
-            val categoriesToUpdate = libraryPreferences.libraryUpdateCategories().get().map(String::toInt)
+            val categoriesToUpdate = libraryPreferences.libraryUpdateCategories().get().map { it.toLong() }
             val listToInclude = if (categoriesToUpdate.isNotEmpty()) {
                 libraryManga.filter { it.category in categoriesToUpdate }
             } else {
                 libraryManga
             }
 
-            val categoriesToExclude = libraryPreferences.libraryUpdateCategoriesExclude().get().map(String::toInt)
+            val categoriesToExclude = libraryPreferences.libraryUpdateCategoriesExclude().get().map { it.toLong() }
             val listToExclude = if (categoriesToExclude.isNotEmpty()) {
                 libraryManga.filter { it.category in categoriesToExclude }
             } else {
@@ -285,12 +283,12 @@ class LibraryUpdateService(
         }
 
         mangaToUpdate = listToUpdate
-            .distinctBy { it.id }
-            .sortedBy { it.title }
+            .distinctBy { it.manga.id }
+            .sortedBy { it.manga.title }
 
         // Warn when excessively checking a single source
         val maxUpdatesFromSource = mangaToUpdate
-            .groupBy { it.source }
+            .groupBy { it.manga.source }
             .filterKeys { sourceManager.get(it) !is UnmeteredSource }
             .maxOfOrNull { it.value.size } ?: 0
         if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
@@ -309,8 +307,8 @@ class LibraryUpdateService(
     private suspend fun updateChapterList() {
         val semaphore = Semaphore(5)
         val progressCount = AtomicInteger(0)
-        val currentlyUpdatingManga = CopyOnWriteArrayList<LibraryManga>()
-        val newUpdates = CopyOnWriteArrayList<Pair<DomainManga, Array<DomainChapter>>>()
+        val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
+        val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<DomainChapter>>>()
         val skippedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
         val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
         val hasDownloads = AtomicBoolean(false)
@@ -319,60 +317,58 @@ class LibraryUpdateService(
         val restrictions = libraryPreferences.libraryUpdateMangaRestriction().get()
 
         withIOContext {
-            mangaToUpdate.groupBy { it.source }
+            mangaToUpdate.groupBy { it.manga.source }
                 .values
                 .map { mangaInSource ->
                     async {
                         semaphore.withPermit {
-                            mangaInSource.forEach { manga ->
+                            mangaInSource.forEach { libraryManga ->
+                                val manga = libraryManga.manga
                                 if (updateJob?.isActive != true) {
                                     return@async
                                 }
 
-                                // Don't continue to update if manga not in library
-                                manga.id?.let { getManga.await(it) } ?: return@forEach
+                                // Don't continue to update if manga is not in library
+                                manga.id.let { getManga.await(it) } ?: return@forEach
 
                                 withUpdateNotification(
                                     currentlyUpdatingManga,
                                     progressCount,
                                     manga,
-                                ) { mangaWithNotif ->
+                                ) {
                                     try {
                                         when {
-                                            MANGA_NON_COMPLETED in restrictions && mangaWithNotif.status == SManga.COMPLETED ->
-                                                skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_completed))
+                                            MANGA_NON_COMPLETED in restrictions && manga.status.toInt() == SManga.COMPLETED ->
+                                                skippedUpdates.add(manga to getString(R.string.skipped_reason_completed))
 
-                                            MANGA_HAS_UNREAD in restrictions && mangaWithNotif.unreadCount != 0 ->
-                                                skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_caught_up))
+                                            MANGA_HAS_UNREAD in restrictions && libraryManga.unreadCount != 0L ->
+                                                skippedUpdates.add(manga to getString(R.string.skipped_reason_not_caught_up))
 
-                                            MANGA_NON_READ in restrictions && mangaWithNotif.totalChapters > 0 && !mangaWithNotif.hasStarted ->
-                                                skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_started))
+                                            MANGA_NON_READ in restrictions && libraryManga.totalChapters > 0L && !libraryManga.hasStarted ->
+                                                skippedUpdates.add(manga to getString(R.string.skipped_reason_not_started))
 
-                                            mangaWithNotif.update_strategy != UpdateStrategy.ALWAYS_UPDATE ->
-                                                skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_always_update))
+                                            manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE ->
+                                                skippedUpdates.add(manga to getString(R.string.skipped_reason_not_always_update))
 
                                             else -> {
-                                                // Convert to the manga that contains new chapters
-                                                mangaWithNotif.toDomainManga()?.let { domainManga ->
-                                                    val newChapters = updateManga(domainManga)
-                                                    val newDbChapters = newChapters.map { it.toDbChapter() }
-
-                                                    if (newChapters.isNotEmpty()) {
-                                                        val categoryIds = getCategories.await(domainManga.id).map { it.id }
-                                                        if (domainManga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
-                                                            downloadChapters(mangaWithNotif, newDbChapters)
-                                                            hasDownloads.set(true)
-                                                        }
-
-                                                        // Convert to the manga that contains new chapters
-                                                        newUpdates.add(
-                                                            mangaWithNotif.toDomainManga()!! to
-                                                                newDbChapters
-                                                                    .map { it.toDomainChapter()!! }
-                                                                    .sortedByDescending { it.sourceOrder }
-                                                                    .toTypedArray(),
-                                                        )
+                                                val newChapters = updateManga(manga)
+                                                val newDbChapters = newChapters.map { it.toDbChapter() }
+
+                                                if (newChapters.isNotEmpty()) {
+                                                    val categoryIds = getCategories.await(manga.id).map { it.id }
+                                                    if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
+                                                        downloadChapters(manga, newDbChapters)
+                                                        hasDownloads.set(true)
                                                     }
+
+                                                    // Convert to the manga that contains new chapters
+                                                    newUpdates.add(
+                                                        manga to
+                                                            newDbChapters
+                                                                .map { it.toDomainChapter()!! }
+                                                                .sortedByDescending { it.sourceOrder }
+                                                                .toTypedArray(),
+                                                    )
                                                 }
                                             }
                                         }
@@ -383,11 +379,11 @@ class LibraryUpdateService(
                                             is SourceManager.SourceNotInstalledException -> getString(R.string.loader_not_implemented_error)
                                             else -> e.message
                                         }
-                                        failedUpdates.add(mangaWithNotif to errorMessage)
+                                        failedUpdates.add(manga to errorMessage)
                                     }
 
                                     if (libraryPreferences.autoUpdateTrackers().get()) {
-                                        updateTrackings(mangaWithNotif, loggedServices)
+                                        updateTrackings(manga, loggedServices)
                                     }
                                 }
                             }
@@ -423,7 +419,7 @@ class LibraryUpdateService(
     private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
         // We don't want to start downloading while the library is updating, because websites
         // may don't like it and they could ban the user.
-        downloadManager.downloadChapters(manga.toDomainManga()!!, chapters, false)
+        downloadManager.downloadChapters(manga, chapters, false)
     }
 
     /**
@@ -432,7 +428,7 @@ class LibraryUpdateService(
      * @param manga the manga to update.
      * @return a pair of the inserted and removed chapters.
      */
-    private suspend fun updateManga(manga: DomainManga): List<DomainChapter> {
+    private suspend fun updateManga(manga: Manga): List<DomainChapter> {
         val source = sourceManager.getOrStub(manga.source)
 
         // Update manga metadata if needed
@@ -455,15 +451,16 @@ class LibraryUpdateService(
     private suspend fun updateCovers() {
         val semaphore = Semaphore(5)
         val progressCount = AtomicInteger(0)
-        val currentlyUpdatingManga = CopyOnWriteArrayList<LibraryManga>()
+        val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
 
         withIOContext {
-            mangaToUpdate.groupBy { it.source }
+            mangaToUpdate.groupBy { it.manga.source }
                 .values
                 .map { mangaInSource ->
                     async {
                         semaphore.withPermit {
-                            mangaInSource.forEach { manga ->
+                            mangaInSource.forEach { libraryManga ->
+                                val manga = libraryManga.manga
                                 if (updateJob?.isActive != true) {
                                     return@async
                                 }
@@ -472,14 +469,14 @@ class LibraryUpdateService(
                                     currentlyUpdatingManga,
                                     progressCount,
                                     manga,
-                                ) { mangaWithNotif ->
-                                    val source = sourceManager.get(mangaWithNotif.source) ?: return@withUpdateNotification
+                                ) {
+                                    val source = sourceManager.get(manga.source) ?: return@withUpdateNotification
                                     try {
-                                        val networkManga = source.getMangaDetails(mangaWithNotif.copy())
-                                        mangaWithNotif.prepUpdateCover(coverCache, networkManga, true)
-                                        mangaWithNotif.copyFrom(networkManga)
+                                        val networkManga = source.getMangaDetails(manga.toSManga())
+                                        val updatedManga = manga.prepUpdateCover(coverCache, networkManga, true)
+                                            .copyFrom(networkManga)
                                         try {
-                                            updateManga.await(mangaWithNotif.toDomainManga()!!.toMangaUpdate())
+                                            updateManga.await(updatedManga.toMangaUpdate())
                                         } catch (e: Exception) {
                                             logcat(LogPriority.ERROR) { "Manga doesn't exist anymore" }
                                         }
@@ -506,12 +503,13 @@ class LibraryUpdateService(
         var progressCount = 0
         val loggedServices = trackManager.services.filter { it.isLogged }
 
-        mangaToUpdate.forEach { manga ->
+        mangaToUpdate.forEach { libraryManga ->
+            val manga = libraryManga.manga
             if (updateJob?.isActive != true) {
                 return
             }
 
-            notifier.showProgressNotification(listOf(manga.toDomainManga()!!), progressCount++, mangaToUpdate.size)
+            notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
 
             // Update the tracking details.
             updateTrackings(manga, loggedServices)
@@ -520,8 +518,8 @@ class LibraryUpdateService(
         notifier.cancelProgressNotification()
     }
 
-    private suspend fun updateTrackings(manga: LibraryManga, loggedServices: List<TrackService>) {
-        getTracks.await(manga.id!!)
+    private suspend fun updateTrackings(manga: Manga, loggedServices: List<TrackService>) {
+        getTracks.await(manga.id)
             .map { track ->
                 supervisorScope {
                     async {
@@ -532,7 +530,7 @@ class LibraryUpdateService(
                                 insertTrack.await(updatedTrack.toDomainTrack()!!)
 
                                 if (service is EnhancedTrackService) {
-                                    val chapters = getChapterByMangaId.await(manga.id!!)
+                                    val chapters = getChapterByMangaId.await(manga.id)
                                     syncChaptersWithTrackServiceTwoWay.await(chapters, track, service)
                                 }
                             } catch (e: Throwable) {
@@ -547,10 +545,10 @@ class LibraryUpdateService(
     }
 
     private suspend fun withUpdateNotification(
-        updatingManga: CopyOnWriteArrayList<LibraryManga>,
+        updatingManga: CopyOnWriteArrayList<Manga>,
         completed: AtomicInteger,
-        manga: LibraryManga,
-        block: suspend (LibraryManga) -> Unit,
+        manga: Manga,
+        block: suspend () -> Unit,
     ) {
         if (updateJob?.isActive != true) {
             return
@@ -558,12 +556,12 @@ class LibraryUpdateService(
 
         updatingManga.add(manga)
         notifier.showProgressNotification(
-            updatingManga.map { it.toDomainManga()!! },
+            updatingManga,
             completed.get(),
             mangaToUpdate.size,
         )
 
-        block(manga)
+        block()
 
         if (updateJob?.isActive != true) {
             return
@@ -572,7 +570,7 @@ class LibraryUpdateService(
         updatingManga.remove(manga)
         completed.getAndIncrement()
         notifier.showProgressNotification(
-            updatingManga.map { it.toDomainManga()!! },
+            updatingManga,
             completed.get(),
             mangaToUpdate.size,
         )

+ 4 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt

@@ -16,7 +16,6 @@ import eu.kanade.presentation.components.ChangeCategoryDialog
 import eu.kanade.presentation.components.DeleteLibraryMangaDialog
 import eu.kanade.presentation.library.LibraryScreen
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.toDomainManga
 import eu.kanade.tachiyomi.data.library.LibraryUpdateService
 import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
 import eu.kanade.tachiyomi.ui.base.controller.RootController
@@ -197,7 +196,7 @@ class LibraryController(
     private fun showMangaCategoriesDialog() {
         viewScope.launchIO {
             // Create a copy of selected manga
-            val mangaList = presenter.selection.mapNotNull { it.toDomainManga() }.toList()
+            val mangaList = presenter.selection.map { it.manga }
 
             // Hide the default category because it has a different behavior than the ones from db.
             val categories = presenter.categories.filter { it.id != 0L }
@@ -219,18 +218,18 @@ class LibraryController(
 
     private fun downloadUnreadChapters() {
         val mangaList = presenter.selection.toList()
-        presenter.downloadUnreadChapters(mangaList.mapNotNull { it.toDomainManga() })
+        presenter.downloadUnreadChapters(mangaList.map { it.manga })
         presenter.clearSelection()
     }
 
     private fun markReadStatus(read: Boolean) {
         val mangaList = presenter.selection.toList()
-        presenter.markReadStatus(mangaList.mapNotNull { it.toDomainManga() }, read)
+        presenter.markReadStatus(mangaList.map { it.manga }, read)
         presenter.clearSelection()
     }
 
     private fun showDeleteMangaDialog() {
-        val mangaList = presenter.selection.mapNotNull { it.toDomainManga() }.toList()
+        val mangaList = presenter.selection.map { it.manga }
         presenter.dialog = LibraryPresenter.Dialog.DeleteManga(mangaList)
     }
 }

+ 14 - 14
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt

@@ -1,19 +1,19 @@
 package eu.kanade.tachiyomi.ui.library
 
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.getNameForMangaInfo
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
 class LibraryItem(
-    val manga: LibraryManga,
+    val libraryManga: LibraryManga,
     private val sourceManager: SourceManager = Injekt.get(),
 ) {
 
     var displayMode: Long = -1
-    var downloadCount = -1
-    var unreadCount = -1
+    var downloadCount: Long = -1
+    var unreadCount: Long = -1
     var isLocal = false
     var sourceLanguage = ""
 
@@ -24,12 +24,12 @@ class LibraryItem(
      * @return true if the manga should be included, false otherwise.
      */
     fun filter(constraint: String): Boolean {
-        val sourceName by lazy { sourceManager.getOrStub(manga.source).getNameForMangaInfo() }
-        val genres by lazy { manga.getGenres() }
-        return manga.title.contains(constraint, true) ||
-            (manga.author?.contains(constraint, true) ?: false) ||
-            (manga.artist?.contains(constraint, true) ?: false) ||
-            (manga.description?.contains(constraint, true) ?: false) ||
+        val sourceName by lazy { sourceManager.getOrStub(libraryManga.manga.source).getNameForMangaInfo() }
+        val genres by lazy { libraryManga.manga.genre }
+        return libraryManga.manga.title.contains(constraint, true) ||
+            (libraryManga.manga.author?.contains(constraint, true) ?: false) ||
+            (libraryManga.manga.artist?.contains(constraint, true) ?: false) ||
+            (libraryManga.manga.description?.contains(constraint, true) ?: false) ||
             if (constraint.contains(",")) {
                 constraint.split(",").all { containsSourceOrGenre(it.trim(), sourceName, genres) }
             } else {
@@ -73,7 +73,7 @@ class LibraryItem(
 
         other as LibraryItem
 
-        if (manga != other.manga) return false
+        if (libraryManga != other.libraryManga) return false
         if (sourceManager != other.sourceManager) return false
         if (displayMode != other.displayMode) return false
         if (downloadCount != other.downloadCount) return false
@@ -85,11 +85,11 @@ class LibraryItem(
     }
 
     override fun hashCode(): Int {
-        var result = manga.hashCode()
+        var result = libraryManga.hashCode()
         result = 31 * result + sourceManager.hashCode()
         result = 31 * result + displayMode.hashCode()
-        result = 31 * result + downloadCount
-        result = 31 * result + unreadCount
+        result = 31 * result + downloadCount.toInt()
+        result = 31 * result + unreadCount.toInt()
         result = 31 * result + isLocal.hashCode()
         result = 31 * result + sourceLanguage.hashCode()
         return result

+ 32 - 32
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt

@@ -23,6 +23,7 @@ import eu.kanade.domain.category.model.Category
 import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
 import eu.kanade.domain.chapter.interactor.SetReadStatus
 import eu.kanade.domain.chapter.model.toDbChapter
+import eu.kanade.domain.library.model.LibraryManga
 import eu.kanade.domain.library.model.LibrarySort
 import eu.kanade.domain.library.model.sort
 import eu.kanade.domain.library.service.LibraryPreferences
@@ -38,7 +39,6 @@ import eu.kanade.presentation.library.LibraryStateImpl
 import eu.kanade.presentation.library.components.LibraryToolbarTitle
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.cache.CoverCache
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.data.database.models.toDomainManga
 import eu.kanade.tachiyomi.data.download.DownloadManager
 import eu.kanade.tachiyomi.data.track.TrackManager
@@ -185,9 +185,9 @@ class LibraryPresenter(
         val filterFnDownloaded: (LibraryItem) -> Boolean = downloaded@{ item ->
             if (!downloadedOnly && filterDownloaded == State.IGNORE.value) return@downloaded true
             val isDownloaded = when {
-                item.manga.toDomainManga()!!.isLocal() -> true
-                item.downloadCount != -1 -> item.downloadCount > 0
-                else -> downloadManager.getDownloadCount(item.manga.toDomainManga()!!) > 0
+                item.libraryManga.manga.isLocal() -> true
+                item.downloadCount != -1L -> item.downloadCount > 0
+                else -> downloadManager.getDownloadCount(item.libraryManga.manga) > 0
             }
 
             return@downloaded if (downloadedOnly || filterDownloaded == State.INCLUDE.value) {
@@ -199,7 +199,7 @@ class LibraryPresenter(
 
         val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item ->
             if (filterUnread == State.IGNORE.value) return@unread true
-            val isUnread = item.manga.unreadCount != 0
+            val isUnread = item.libraryManga.unreadCount != 0L
 
             return@unread if (filterUnread == State.INCLUDE.value) {
                 isUnread
@@ -210,7 +210,7 @@ class LibraryPresenter(
 
         val filterFnStarted: (LibraryItem) -> Boolean = started@{ item ->
             if (filterStarted == State.IGNORE.value) return@started true
-            val hasStarted = item.manga.hasStarted
+            val hasStarted = item.libraryManga.hasStarted
 
             return@started if (filterStarted == State.INCLUDE.value) {
                 hasStarted
@@ -221,7 +221,7 @@ class LibraryPresenter(
 
         val filterFnCompleted: (LibraryItem) -> Boolean = completed@{ item ->
             if (filterCompleted == State.IGNORE.value) return@completed true
-            val isCompleted = item.manga.status == SManga.COMPLETED
+            val isCompleted = item.libraryManga.manga.status.toInt() == SManga.COMPLETED
 
             return@completed if (filterCompleted == State.INCLUDE.value) {
                 isCompleted
@@ -233,7 +233,7 @@ class LibraryPresenter(
         val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item ->
             if (isNotAnyLoggedIn) return@tracking true
 
-            val trackedManga = trackMap[item.manga.id ?: -1]
+            val trackedManga = trackMap[item.libraryManga.manga.id]
 
             val containsExclude = loggedInServices.filterValues { it == State.EXCLUDE.value }
             val containsInclude = loggedInServices.filterValues { it == State.INCLUDE.value }
@@ -281,28 +281,28 @@ class LibraryPresenter(
         for ((_, itemList) in map) {
             for (item in itemList) {
                 item.downloadCount = if (showDownloadBadges) {
-                    downloadManager.getDownloadCount(item.manga.toDomainManga()!!)
+                    downloadManager.getDownloadCount(item.libraryManga.manga).toLong()
                 } else {
                     // Unset download count if not enabled
                     -1
                 }
 
                 item.unreadCount = if (showUnreadBadges) {
-                    item.manga.unreadCount
+                    item.libraryManga.unreadCount
                 } else {
                     // Unset unread count if not enabled
                     -1
                 }
 
                 item.isLocal = if (showLocalBadges) {
-                    item.manga.toDomainManga()!!.isLocal()
+                    item.libraryManga.manga.isLocal()
                 } else {
                     // Hide / Unset local badge if not enabled
                     false
                 }
 
                 item.sourceLanguage = if (showLanguageBadges) {
-                    sourceManager.getOrStub(item.manga.source).lang.uppercase()
+                    sourceManager.getOrStub(item.libraryManga.manga.source).lang.uppercase()
                 } else {
                     // Unset source language if not enabled
                     ""
@@ -354,43 +354,43 @@ class LibraryPresenter(
             strength = Collator.PRIMARY
         }
         val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
-            val sort = sortModes[i1.manga.category.toLong()]!!
+            val sort = sortModes[i1.libraryManga.category]!!
             when (sort.type) {
                 LibrarySort.Type.Alphabetical -> {
-                    collator.compare(i1.manga.title.lowercase(locale), i2.manga.title.lowercase(locale))
+                    collator.compare(i1.libraryManga.manga.title.lowercase(locale), i2.libraryManga.manga.title.lowercase(locale))
                 }
                 LibrarySort.Type.LastRead -> {
-                    val manga1LastRead = lastReadManga[i1.manga.id!!] ?: 0
-                    val manga2LastRead = lastReadManga[i2.manga.id!!] ?: 0
+                    val manga1LastRead = lastReadManga[i1.libraryManga.manga.id] ?: 0
+                    val manga2LastRead = lastReadManga[i2.libraryManga.manga.id] ?: 0
                     manga1LastRead.compareTo(manga2LastRead)
                 }
                 LibrarySort.Type.LastUpdate -> {
-                    i1.manga.last_update.compareTo(i2.manga.last_update)
+                    i1.libraryManga.manga.lastUpdate.compareTo(i2.libraryManga.manga.lastUpdate)
                 }
                 LibrarySort.Type.UnreadCount -> when {
                     // Ensure unread content comes first
-                    i1.manga.unreadCount == i2.manga.unreadCount -> 0
-                    i1.manga.unreadCount == 0 -> if (sort.isAscending) 1 else -1
-                    i2.manga.unreadCount == 0 -> if (sort.isAscending) -1 else 1
-                    else -> i1.manga.unreadCount.compareTo(i2.manga.unreadCount)
+                    i1.libraryManga.unreadCount == i2.libraryManga.unreadCount -> 0
+                    i1.libraryManga.unreadCount == 0L -> if (sort.isAscending) 1 else -1
+                    i2.libraryManga.unreadCount == 0L -> if (sort.isAscending) -1 else 1
+                    else -> i1.libraryManga.unreadCount.compareTo(i2.libraryManga.unreadCount)
                 }
                 LibrarySort.Type.TotalChapters -> {
-                    i1.manga.totalChapters.compareTo(i2.manga.totalChapters)
+                    i1.libraryManga.totalChapters.compareTo(i2.libraryManga.totalChapters)
                 }
                 LibrarySort.Type.LatestChapter -> {
-                    val manga1latestChapter = latestChapterManga[i1.manga.id!!]
+                    val manga1latestChapter = latestChapterManga[i1.libraryManga.manga.id]
                         ?: latestChapterManga.size
-                    val manga2latestChapter = latestChapterManga[i2.manga.id!!]
+                    val manga2latestChapter = latestChapterManga[i2.libraryManga.manga.id]
                         ?: latestChapterManga.size
                     manga1latestChapter.compareTo(manga2latestChapter)
                 }
                 LibrarySort.Type.ChapterFetchDate -> {
-                    val manga1chapterFetchDate = chapterFetchDateManga[i1.manga.id!!] ?: 0
-                    val manga2chapterFetchDate = chapterFetchDateManga[i2.manga.id!!] ?: 0
+                    val manga1chapterFetchDate = chapterFetchDateManga[i1.libraryManga.manga.id] ?: 0
+                    val manga2chapterFetchDate = chapterFetchDateManga[i2.libraryManga.manga.id] ?: 0
                     manga1chapterFetchDate.compareTo(manga2chapterFetchDate)
                 }
                 LibrarySort.Type.DateAdded -> {
-                    i1.manga.date_added.compareTo(i2.manga.date_added)
+                    i1.libraryManga.manga.dateAdded.compareTo(i1.libraryManga.manga.dateAdded)
                 }
                 else -> throw IllegalStateException("Invalid SortModeSetting: ${sort.type}")
             }
@@ -419,7 +419,7 @@ class LibraryPresenter(
                 list.map { libraryManga ->
                     // Display mode based on user preference: take it from global library setting or category
                     LibraryItem(libraryManga)
-                }.groupBy { it.manga.category.toLong() }
+                }.groupBy { it.libraryManga.category.toLong() }
             }
         return combine(categoriesFlow, libraryMangasFlow) { dbCategories, libraryManga ->
             val categories = if (libraryManga.isNotEmpty() && libraryManga.containsKey(0).not()) {
@@ -631,7 +631,7 @@ class LibraryPresenter(
             val count = when {
                 category == null || mangaCountVisibility.not() -> null
                 tabVisibility.not() -> loadedManga[category.id]?.size
-                else -> loadedManga.values.flatten().distinctBy { it.manga.id }.size
+                else -> loadedManga.values.flatten().distinctBy { it.libraryManga.manga.id }.size
             }
 
             value = when (category) {
@@ -665,7 +665,7 @@ class LibraryPresenter(
 
     fun toggleSelection(manga: LibraryManga) {
         val mutableList = state.selection.toMutableList()
-        if (selection.fastAny { it.id == manga.id }) {
+        if (selection.fastAny { it.manga.id == manga.manga.id }) {
             mutableList.remove(manga)
         } else {
             mutableList.add(manga)
@@ -677,13 +677,13 @@ class LibraryPresenter(
         val category = categories[index]
         val items = loadedManga[category.id] ?: emptyList()
         state.selection = state.selection.toMutableList().apply {
-            addAll(items.filterNot { it.manga in selection }.map { it.manga })
+            addAll(items.filterNot { it.libraryManga in selection }.map { it.libraryManga })
         }
     }
 
     fun invertSelection(index: Int) {
         val category = categories[index]
-        val items = (loadedManga[category.id] ?: emptyList()).map { it.manga }
+        val items = (loadedManga[category.id] ?: emptyList()).map { it.libraryManga }
         state.selection = items.filterNot { it in selection }
     }
 

+ 10 - 10
app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt

@@ -20,26 +20,26 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
 /**
  * Call before updating [Manga.thumbnail_url] to ensure old cover can be cleared from cache
  */
-fun Manga.prepUpdateCover(coverCache: CoverCache, remoteManga: SManga, refreshSameUrl: Boolean) {
+fun DomainManga.prepUpdateCover(coverCache: CoverCache, remoteManga: SManga, refreshSameUrl: Boolean): DomainManga {
     // Never refresh covers if the new url is null, as the current url has possibly become invalid
-    val newUrl = remoteManga.thumbnail_url ?: return
+    val newUrl = remoteManga.thumbnail_url ?: return this
 
     // Never refresh covers if the url is empty to avoid "losing" existing covers
-    if (newUrl.isEmpty()) return
+    if (newUrl.isEmpty()) return this
 
-    if (!refreshSameUrl && thumbnail_url == newUrl) return
+    if (!refreshSameUrl && thumbnailUrl == newUrl) return this
 
-    val domainManga = toDomainManga()!!
-    when {
-        domainManga.isLocal() -> {
-            cover_last_modified = Date().time
+    return when {
+        isLocal() -> {
+            this.copy(coverLastModified = Date().time)
         }
-        domainManga.hasCustomCover(coverCache) -> {
+        hasCustomCover(coverCache) -> {
             coverCache.deleteFromCache(this, false)
+            this
         }
         else -> {
-            cover_last_modified = Date().time
             coverCache.deleteFromCache(this, false)
+            this.copy(coverLastModified = Date().time)
         }
     }
 }