mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Move LibraryManga to domain layer (#8126)
				
					
				
			This commit is contained in:
		| @@ -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, | ||||
|         ) | ||||
|     } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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,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,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 { | ||||
|   | ||||
| @@ -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, | ||||
|                     ) | ||||
|                 }, | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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) | ||||
|             } | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 = {}, | ||||
|   | ||||
| @@ -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( | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
| @@ -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() } | ||||
|                                                 val newChapters = updateManga(manga) | ||||
|                                                 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(), | ||||
|                                                         ) | ||||
|                                                 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, | ||||
|         ) | ||||
|   | ||||
| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user