Display total chapters on duplicates list items (#1963)
(cherry picked from commit 12abd9938b7c235d6a1c02391624703476c1f339) # Conflicts: # CHANGELOG.md # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt # data/src/main/java/tachiyomi/data/manga/MangaMapper.kt
This commit is contained in:
parent
f1aed0d8b9
commit
5e0f730159
@ -3,6 +3,7 @@ package eu.kanade.presentation.manga
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -63,10 +64,14 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
import tachiyomi.presentation.core.components.BadgeGroup
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -74,7 +79,7 @@ import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun DuplicateMangaDialog(
|
||||
duplicates: List<Manga>,
|
||||
duplicates: List<MangaWithChapterCount>,
|
||||
onDismissRequest: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
onOpenManga: (manga: Manga) -> Unit,
|
||||
@ -118,14 +123,14 @@ fun DuplicateMangaDialog(
|
||||
) {
|
||||
items(
|
||||
items = duplicates,
|
||||
key = { it.id },
|
||||
key = { it.manga.id },
|
||||
) {
|
||||
DuplicateMangaListItem(
|
||||
manga = it,
|
||||
getSource = { sourceManager.getOrStub(it.source) },
|
||||
onMigrate = { onMigrate(it) },
|
||||
duplicate = it,
|
||||
getSource = { sourceManager.getOrStub(it.manga.source) },
|
||||
onMigrate = { onMigrate(it.manga) },
|
||||
onDismissRequest = onDismissRequest,
|
||||
onOpenManga = { onOpenManga(it) },
|
||||
onOpenManga = { onOpenManga(it.manga) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -165,13 +170,14 @@ fun DuplicateMangaDialog(
|
||||
|
||||
@Composable
|
||||
private fun DuplicateMangaListItem(
|
||||
manga: Manga,
|
||||
duplicate: MangaWithChapterCount,
|
||||
getSource: () -> Source,
|
||||
onDismissRequest: () -> Unit,
|
||||
onOpenManga: () -> Unit,
|
||||
onMigrate: () -> Unit,
|
||||
) {
|
||||
val source = getSource()
|
||||
val manga = duplicate.manga
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(MangaCardWidth)
|
||||
@ -186,13 +192,30 @@ private fun DuplicateMangaListItem(
|
||||
)
|
||||
.padding(MaterialTheme.padding.small),
|
||||
) {
|
||||
MangaCover.Book(
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
Box {
|
||||
MangaCover.Book(
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
BadgeGroup(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.TopStart),
|
||||
) {
|
||||
Badge(
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
textColor = MaterialTheme.colorScheme.onSecondary,
|
||||
text = pluralStringResource(
|
||||
MR.plurals.manga_num_chapters,
|
||||
duplicate.chapterCount.toInt(),
|
||||
duplicate.chapterCount,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(MaterialTheme.padding.extraSmall))
|
||||
|
||||
@ -292,7 +315,7 @@ private fun MangaDetailRow(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getMaximumMangaCardHeight(duplicates: List<Manga>): Dp {
|
||||
private fun getMaximumMangaCardHeight(duplicates: List<MangaWithChapterCount>): Dp {
|
||||
val density = LocalDensity.current
|
||||
val typography = MaterialTheme.typography
|
||||
val textMeasurer = rememberTextMeasurer()
|
||||
@ -320,7 +343,7 @@ private fun getMaximumMangaCardHeight(duplicates: List<Manga>): Dp {
|
||||
) {
|
||||
duplicates.fastMaxOfOrNull {
|
||||
calculateMangaCardHeight(
|
||||
manga = it,
|
||||
manga = it.manga,
|
||||
density = density,
|
||||
typography = typography,
|
||||
textMeasurer = textMeasurer,
|
||||
|
@ -65,6 +65,7 @@ import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import tachiyomi.domain.manga.interactor.GetFlatMetadataById
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.source.interactor.DeleteSavedSearchById
|
||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||
@ -393,7 +394,7 @@ open class BrowseSourceScreenModel(
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
suspend fun getDuplicateLibraryManga(manga: Manga): List<Manga> {
|
||||
suspend fun getDuplicateLibraryManga(manga: Manga): List<MangaWithChapterCount> {
|
||||
return getDuplicateLibraryManga.invoke(manga)
|
||||
}
|
||||
|
||||
@ -444,7 +445,7 @@ open class BrowseSourceScreenModel(
|
||||
sealed interface Dialog {
|
||||
data object Filter : Dialog
|
||||
data class RemoveManga(val manga: Manga) : Dialog
|
||||
data class AddDuplicateManga(val manga: Manga, val duplicates: List<Manga>) : Dialog
|
||||
data class AddDuplicateManga(val manga: Manga, val duplicates: List<MangaWithChapterCount>) : Dialog
|
||||
data class ChangeMangaCategory(
|
||||
val manga: Manga,
|
||||
val initialSelection: ImmutableList<CheckboxState.State<Category>>,
|
||||
|
@ -40,6 +40,7 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -246,7 +247,7 @@ class HistoryScreenModel(
|
||||
sealed interface Dialog {
|
||||
data object DeleteAll : Dialog
|
||||
data class Delete(val history: HistoryWithRelations) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicates: List<Manga>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicates: List<MangaWithChapterCount>) : Dialog
|
||||
data class ChangeCategory(
|
||||
val manga: Manga,
|
||||
val initialSelection: ImmutableList<CheckboxState<Category>>,
|
||||
|
@ -125,6 +125,7 @@ import tachiyomi.domain.manga.interactor.UpdateMergedSettings
|
||||
import tachiyomi.domain.manga.model.CustomMangaInfo
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.model.MergeMangaSettingsUpdate
|
||||
import tachiyomi.domain.manga.model.MergedMangaReference
|
||||
import tachiyomi.domain.manga.model.applyFilter
|
||||
@ -1653,7 +1654,7 @@ class MangaScreenModel(
|
||||
val initialSelection: ImmutableList<CheckboxState<Category>>,
|
||||
) : Dialog
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicates: List<Manga>) : Dialog
|
||||
data class DuplicateManga(val manga: Manga, val duplicates: List<MangaWithChapterCount>) : Dialog
|
||||
|
||||
/* SY -->
|
||||
data class Migrate(val newManga: Manga, val oldManga: Manga) : Dialog
|
||||
|
@ -3,6 +3,7 @@ package tachiyomi.data.manga
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.view.LibraryView
|
||||
|
||||
object MangaMapper {
|
||||
@ -143,6 +144,71 @@ object MangaMapper {
|
||||
lastRead = lastRead,
|
||||
)
|
||||
|
||||
fun mapMangaWithChapterCount(
|
||||
id: Long,
|
||||
source: Long,
|
||||
url: String,
|
||||
artist: String?,
|
||||
author: String?,
|
||||
description: String?,
|
||||
genre: List<String>?,
|
||||
title: String,
|
||||
status: Long,
|
||||
thumbnailUrl: String?,
|
||||
favorite: Boolean,
|
||||
lastUpdate: Long?,
|
||||
nextUpdate: Long?,
|
||||
initialized: Boolean,
|
||||
viewerFlags: Long,
|
||||
chapterFlags: Long,
|
||||
coverLastModified: Long,
|
||||
dateAdded: Long,
|
||||
// SY -->
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
filteredScanlators: String?,
|
||||
// SY <--
|
||||
updateStrategy: UpdateStrategy,
|
||||
calculateInterval: Long,
|
||||
lastModifiedAt: Long,
|
||||
favoriteModifiedAt: Long?,
|
||||
version: Long,
|
||||
isSyncing: Long,
|
||||
notes: String,
|
||||
totalCount: Long,
|
||||
): MangaWithChapterCount = MangaWithChapterCount(
|
||||
manga = mapManga(
|
||||
id,
|
||||
source,
|
||||
url,
|
||||
artist,
|
||||
author,
|
||||
description,
|
||||
genre,
|
||||
title,
|
||||
status,
|
||||
thumbnailUrl,
|
||||
favorite,
|
||||
lastUpdate,
|
||||
nextUpdate,
|
||||
initialized,
|
||||
viewerFlags,
|
||||
chapterFlags,
|
||||
coverLastModified,
|
||||
dateAdded,
|
||||
// SY -->
|
||||
null,
|
||||
// SY <--
|
||||
updateStrategy,
|
||||
calculateInterval,
|
||||
lastModifiedAt,
|
||||
favoriteModifiedAt,
|
||||
version,
|
||||
isSyncing,
|
||||
notes,
|
||||
),
|
||||
chapterCount = totalCount,
|
||||
)
|
||||
|
||||
fun mapLibraryView(libraryView: LibraryView): LibraryManga {
|
||||
return LibraryManga(
|
||||
manga = Manga(
|
||||
|
@ -11,6 +11,7 @@ import tachiyomi.data.UpdateStrategyColumnAdapter
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.repository.MangaRepository
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
@ -73,9 +74,9 @@ class MangaRepositoryImpl(
|
||||
return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, MangaMapper::mapManga) }
|
||||
}
|
||||
|
||||
override suspend fun getDuplicateLibraryManga(id: Long, title: String): List<Manga> {
|
||||
override suspend fun getDuplicateLibraryManga(id: Long, title: String): List<MangaWithChapterCount> {
|
||||
return handler.awaitList {
|
||||
mangasQueries.getDuplicateLibraryManga(title, id, MangaMapper::mapManga)
|
||||
mangasQueries.getDuplicateLibraryManga(id, title, MangaMapper::mapMangaWithChapterCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,11 +117,33 @@ WHERE favorite = 1
|
||||
AND source = :sourceId;
|
||||
|
||||
getDuplicateLibraryManga:
|
||||
SELECT *
|
||||
FROM mangas
|
||||
WHERE favorite = 1
|
||||
AND lower(title) LIKE '%' || lower(:title) || '%'
|
||||
AND _id != :id;
|
||||
WITH
|
||||
duplicates AS (
|
||||
SELECT *
|
||||
FROM mangas
|
||||
WHERE favorite = 1
|
||||
AND _id != :id
|
||||
AND lower(title) LIKE '%' || lower(:title) || '%'
|
||||
),
|
||||
chapter_counts AS (
|
||||
SELECT
|
||||
M._id AS manga_id,
|
||||
count(*) AS chapter_count
|
||||
FROM duplicates M
|
||||
JOIN chapters C
|
||||
ON M._id = C.manga_id
|
||||
LEFT JOIN excluded_scanlators ES
|
||||
ON C.manga_id = ES.manga_id
|
||||
AND C.scanlator = ES.scanlator
|
||||
WHERE ES.scanlator IS NULL
|
||||
GROUP BY M._id
|
||||
)
|
||||
SELECT
|
||||
M.*,
|
||||
coalesce(CC.chapter_count, 0) AS chapter_count
|
||||
FROM duplicates M
|
||||
LEFT JOIN chapter_counts CC
|
||||
ON M._id = CC.manga_id;
|
||||
|
||||
getUpcomingManga:
|
||||
SELECT *
|
||||
|
@ -1,13 +1,14 @@
|
||||
package tachiyomi.domain.manga.interactor
|
||||
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.repository.MangaRepository
|
||||
|
||||
class GetDuplicateLibraryManga(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(manga: Manga): List<Manga> {
|
||||
suspend operator fun invoke(manga: Manga): List<MangaWithChapterCount> {
|
||||
return mangaRepository.getDuplicateLibraryManga(manga.id, manga.title.lowercase())
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package tachiyomi.domain.manga.model
|
||||
|
||||
data class MangaWithChapterCount(
|
||||
val manga: Manga,
|
||||
val chapterCount: Long,
|
||||
)
|
@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
|
||||
interface MangaRepository {
|
||||
|
||||
@ -25,7 +26,7 @@ interface MangaRepository {
|
||||
|
||||
fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>>
|
||||
|
||||
suspend fun getDuplicateLibraryManga(id: Long, title: String): List<Manga>
|
||||
suspend fun getDuplicateLibraryManga(id: Long, title: String): List<MangaWithChapterCount>
|
||||
|
||||
suspend fun getUpcomingManga(statuses: Set<Long>): Flow<List<Manga>>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user