Move LibraryManga
to domain layer (#8126)
This commit is contained in:
parent
b04d1e5f50
commit
ea8383978b
20 changed files with 217 additions and 232 deletions
|
@ -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 a new issue