Fix chapter list live update (#7296)
(cherry picked from commit b96686e6ad0b46a586958179e8cbb1d6a9182323) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
This commit is contained in:
parent
e3f577a6e2
commit
f7ccbd24f8
@ -6,6 +6,7 @@ import eu.kanade.domain.chapter.model.Chapter
|
|||||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||||
import eu.kanade.domain.chapter.repository.ChapterRepository
|
import eu.kanade.domain.chapter.repository.ChapterRepository
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
|
||||||
class ChapterRepositoryImpl(
|
class ChapterRepositoryImpl(
|
||||||
@ -96,11 +97,20 @@ class ChapterRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getChapterByMangaId(mangaId: Long): List<Chapter> {
|
override suspend fun getChapterByMangaId(mangaId: Long): List<Chapter> {
|
||||||
return try {
|
return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) }
|
||||||
handler.awaitList { chaptersQueries.getChapterByMangaId(mangaId, chapterMapper) }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logcat(LogPriority.ERROR, e)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getChapterByMangaIdFlow(mangaId: Long): Flow<List<Chapter>> {
|
||||||
|
return handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
override suspend fun getMergedChapterByMangaId(mangaId: Long): List<Chapter> {
|
||||||
|
return handler.awaitList { chaptersQueries.getMergedChaptersByMangaId(mangaId, chapterMapper) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMergedChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>> {
|
||||||
|
return handler.subscribeToList { chaptersQueries.getMergedChaptersByMangaId(mangaId, chapterMapper) }
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ class HistoryRepositoryImpl(
|
|||||||
else -> throw NotImplementedError("Unknown sorting method")
|
else -> throw NotImplementedError("Unknown sorting method")
|
||||||
}
|
}
|
||||||
|
|
||||||
val chapters = handler.awaitList { chaptersQueries.getChapterByMangaId(mangaId, chapterMapper) }
|
val chapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) }
|
||||||
.sortedWith(sortFunction)
|
.sortedWith(sortFunction)
|
||||||
|
|
||||||
val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id }
|
val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id }
|
||||||
|
@ -4,6 +4,8 @@ import eu.kanade.data.chapter.ChapterRepositoryImpl
|
|||||||
import eu.kanade.data.history.HistoryRepositoryImpl
|
import eu.kanade.data.history.HistoryRepositoryImpl
|
||||||
import eu.kanade.data.manga.MangaRepositoryImpl
|
import eu.kanade.data.manga.MangaRepositoryImpl
|
||||||
import eu.kanade.data.source.SourceRepositoryImpl
|
import eu.kanade.data.source.SourceRepositoryImpl
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||||
import eu.kanade.domain.chapter.interactor.ShouldUpdateDbChapter
|
import eu.kanade.domain.chapter.interactor.ShouldUpdateDbChapter
|
||||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||||
@ -55,6 +57,7 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { UpdateManga(get()) }
|
addFactory { UpdateManga(get()) }
|
||||||
|
|
||||||
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
||||||
|
addFactory { GetChapterByMangaId(get()) }
|
||||||
addFactory { UpdateChapter(get()) }
|
addFactory { UpdateChapter(get()) }
|
||||||
addFactory { ShouldUpdateDbChapter() }
|
addFactory { ShouldUpdateDbChapter() }
|
||||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get()) }
|
addFactory { SyncChaptersWithSource(get(), get(), get(), get()) }
|
||||||
@ -87,6 +90,7 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { ToggleExcludeFromDataSaver(get()) }
|
addFactory { ToggleExcludeFromDataSaver(get()) }
|
||||||
addFactory { SetSourceCategories(get()) }
|
addFactory { SetSourceCategories(get()) }
|
||||||
addFactory { ToggleSources(get()) }
|
addFactory { ToggleSources(get()) }
|
||||||
|
addFactory { GetMergedChapterByMangaId(get()) }
|
||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.domain.chapter.repository.ChapterRepository
|
||||||
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import logcat.LogPriority
|
||||||
|
|
||||||
|
class GetChapterByMangaId(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(mangaId: Long): List<Chapter> {
|
||||||
|
return try {
|
||||||
|
chapterRepository.getChapterByMangaId(mangaId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun subscribe(mangaId: Long): Flow<List<Chapter>> {
|
||||||
|
return try {
|
||||||
|
chapterRepository.getChapterByMangaIdFlow(mangaId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
flowOf(emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.domain.chapter.repository.ChapterRepository
|
||||||
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import logcat.LogPriority
|
||||||
|
|
||||||
|
class GetMergedChapterByMangaId(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(mangaId: Long): List<Chapter> {
|
||||||
|
return try {
|
||||||
|
chapterRepository.getMergedChapterByMangaId(mangaId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun subscribe(mangaId: Long): Flow<List<Chapter>> {
|
||||||
|
return try {
|
||||||
|
chapterRepository.getMergedChapterByMangaIdAsFlow(mangaId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
flowOf(emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ class SyncChaptersWithSource(
|
|||||||
private val chapterRepository: ChapterRepository = Injekt.get(),
|
private val chapterRepository: ChapterRepository = Injekt.get(),
|
||||||
private val shouldUpdateDbChapter: ShouldUpdateDbChapter = Injekt.get(),
|
private val shouldUpdateDbChapter: ShouldUpdateDbChapter = Injekt.get(),
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
@ -46,7 +47,7 @@ class SyncChaptersWithSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Chapters from db.
|
// Chapters from db.
|
||||||
val dbChapters = chapterRepository.getChapterByMangaId(manga.id)
|
val dbChapters = getChapterByMangaId.await(manga.id)
|
||||||
|
|
||||||
// Chapters from the source not in db.
|
// Chapters from the source not in db.
|
||||||
val toAdd = mutableListOf<Chapter>()
|
val toAdd = mutableListOf<Chapter>()
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.domain.chapter.repository
|
|||||||
|
|
||||||
import eu.kanade.domain.chapter.model.Chapter
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ChapterRepository {
|
interface ChapterRepository {
|
||||||
|
|
||||||
@ -14,4 +15,12 @@ interface ChapterRepository {
|
|||||||
suspend fun removeChaptersWithIds(chapterIds: List<Long>)
|
suspend fun removeChaptersWithIds(chapterIds: List<Long>)
|
||||||
|
|
||||||
suspend fun getChapterByMangaId(mangaId: Long): List<Chapter>
|
suspend fun getChapterByMangaId(mangaId: Long): List<Chapter>
|
||||||
|
|
||||||
|
suspend fun getChapterByMangaIdFlow(mangaId: Long): Flow<List<Chapter>>
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
suspend fun getMergedChapterByMangaId(mangaId: Long): List<Chapter>
|
||||||
|
|
||||||
|
suspend fun getMergedChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>>
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.all
|
package eu.kanade.tachiyomi.source.online.all
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||||
import eu.kanade.domain.chapter.model.toDbChapter
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
import eu.kanade.domain.manga.model.toDbManga
|
import eu.kanade.domain.manga.model.toDbManga
|
||||||
@ -27,11 +28,11 @@ import exh.source.MERGED_SOURCE_ID
|
|||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
|
||||||
import tachiyomi.source.model.ChapterInfo
|
import tachiyomi.source.model.ChapterInfo
|
||||||
import tachiyomi.source.model.MangaInfo
|
import tachiyomi.source.model.MangaInfo
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -42,6 +43,7 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
|
|||||||
|
|
||||||
class MergedSource : HttpSource() {
|
class MergedSource : HttpSource() {
|
||||||
private val db: DatabaseHelper by injectLazy()
|
private val db: DatabaseHelper by injectLazy()
|
||||||
|
private val getMergedChaptersByMangaId: GetMergedChapterByMangaId by injectLazy()
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val sourceManager: SourceManager by injectLazy()
|
||||||
private val downloadManager: DownloadManager by injectLazy()
|
private val downloadManager: DownloadManager by injectLazy()
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
@ -99,62 +101,61 @@ class MergedSource : HttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO more chapter dedupe
|
// TODO more chapter dedupe
|
||||||
private fun transformMergedChapters(manga: DomainManga, chapterList: List<Chapter>, editScanlators: Boolean, dedupe: Boolean): List<Chapter> {
|
fun transformMergedChapters(mangaId: Long, chapterList: List<DomainChapter>, editScanlators: Boolean, dedupe: Boolean): List<DomainChapter> {
|
||||||
val mangaReferences = db.getMergedMangaReferences(manga.id).executeAsBlocking()
|
val mangaReferences = db.getMergedMangaReferences(mangaId).executeAsBlocking()
|
||||||
if (editScanlators) {
|
val chapters = if (editScanlators) {
|
||||||
val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId }
|
val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId }
|
||||||
chapterList.onEach { chapter ->
|
chapterList.map { chapter ->
|
||||||
val source = sources.firstOrNull { chapter.manga_id == it.second }?.first
|
val source = sources.firstOrNull { chapter.mangaId == it.second }?.first
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
chapter.scanlator = if (chapter.scanlator.isNullOrBlank()) source.name
|
chapter.copy(
|
||||||
else "$source: ${chapter.scanlator}"
|
scanlator = if (chapter.scanlator.isNullOrBlank()) {
|
||||||
}
|
source.name
|
||||||
|
} else {
|
||||||
|
"$source: ${chapter.scanlator}"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else chapter
|
||||||
}
|
}
|
||||||
}
|
} else chapterList
|
||||||
return if (dedupe) dedupeChapterList(mangaReferences, chapterList) else chapterList
|
return if (dedupe) dedupeChapterList(mangaReferences, chapters) else chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getChaptersAsBlocking(manga: DomainManga, editScanlators: Boolean = false, dedupe: Boolean = true): List<Chapter> {
|
fun getChaptersAsBlocking(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List<Chapter> {
|
||||||
return transformMergedChapters(manga, db.getChaptersByMergedMangaId(manga.id).executeAsBlocking(), editScanlators, dedupe)
|
return transformMergedChapters(mangaId, runBlocking { getMergedChaptersByMangaId.await(mangaId) }, editScanlators, dedupe)
|
||||||
|
.map(DomainChapter::toDbChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getChaptersObservable(manga: DomainManga, editScanlators: Boolean = false, dedupe: Boolean = true): Observable<List<Chapter>> {
|
private fun dedupeChapterList(mangaReferences: List<MergedMangaReference>, chapterList: List<DomainChapter>): List<DomainChapter> {
|
||||||
return db.getChaptersByMergedMangaId(manga.id).asRxObservable()
|
|
||||||
.map { chapterList ->
|
|
||||||
transformMergedChapters(manga, chapterList, editScanlators, dedupe)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dedupeChapterList(mangaReferences: List<MergedMangaReference>, chapterList: List<Chapter>): List<Chapter> {
|
|
||||||
return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) {
|
return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) {
|
||||||
MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList
|
MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList
|
||||||
MergedMangaReference.CHAPTER_SORT_PRIORITY -> chapterList
|
MergedMangaReference.CHAPTER_SORT_PRIORITY -> chapterList
|
||||||
MergedMangaReference.CHAPTER_SORT_MOST_CHAPTERS -> {
|
MergedMangaReference.CHAPTER_SORT_MOST_CHAPTERS -> {
|
||||||
findSourceWithMostChapters(chapterList)?.let { mangaId ->
|
findSourceWithMostChapters(chapterList)?.let { mangaId ->
|
||||||
chapterList.filter { it.manga_id == mangaId }
|
chapterList.filter { it.mangaId == mangaId }
|
||||||
} ?: chapterList
|
} ?: chapterList
|
||||||
}
|
}
|
||||||
MergedMangaReference.CHAPTER_SORT_HIGHEST_CHAPTER_NUMBER -> {
|
MergedMangaReference.CHAPTER_SORT_HIGHEST_CHAPTER_NUMBER -> {
|
||||||
findSourceWithHighestChapterNumber(chapterList)?.let { mangaId ->
|
findSourceWithHighestChapterNumber(chapterList)?.let { mangaId ->
|
||||||
chapterList.filter { it.manga_id == mangaId }
|
chapterList.filter { it.mangaId == mangaId }
|
||||||
} ?: chapterList
|
} ?: chapterList
|
||||||
}
|
}
|
||||||
else -> chapterList
|
else -> chapterList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findSourceWithMostChapters(chapterList: List<Chapter>): Long? {
|
private fun findSourceWithMostChapters(chapterList: List<DomainChapter>): Long? {
|
||||||
return chapterList.groupBy { it.manga_id }.maxByOrNull { it.value.size }?.key
|
return chapterList.groupBy { it.mangaId }.maxByOrNull { it.value.size }?.key
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findSourceWithHighestChapterNumber(chapterList: List<Chapter>): Long? {
|
private fun findSourceWithHighestChapterNumber(chapterList: List<DomainChapter>): Long? {
|
||||||
return chapterList.maxByOrNull { it.chapter_number }?.manga_id
|
return chapterList.maxByOrNull { it.chapterNumber }?.mangaId
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchChaptersForMergedManga(manga: DomainManga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true): List<Chapter> {
|
suspend fun fetchChaptersForMergedManga(manga: DomainManga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true): List<Chapter> {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
fetchChaptersAndSync(manga, downloadChapters)
|
fetchChaptersAndSync(manga, downloadChapters)
|
||||||
getChaptersAsBlocking(manga, editScanlators, dedupe)
|
getChaptersAsBlocking(manga.id, editScanlators, dedupe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import eu.kanade.tachiyomi.data.database.models.Category
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
@ -642,7 +641,7 @@ class LibraryPresenter(
|
|||||||
val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource
|
val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource
|
||||||
val mergedMangas = db.getMergedMangas(manga.id!!).executeAsBlocking()
|
val mergedMangas = db.getMergedMangas(manga.id!!).executeAsBlocking()
|
||||||
mergedSource
|
mergedSource
|
||||||
.getChaptersAsBlocking(manga.toDomainManga()!!)
|
.getChaptersAsBlocking(manga.id!!)
|
||||||
.filter { !it.read }
|
.filter { !it.read }
|
||||||
.groupBy { it.manga_id!! }
|
.groupBy { it.manga_id!! }
|
||||||
.forEach ab@{ (mangaId, chapters) ->
|
.forEach ab@{ (mangaId, chapters) ->
|
||||||
@ -712,7 +711,7 @@ class LibraryPresenter(
|
|||||||
mangas.forEach { manga ->
|
mangas.forEach { manga ->
|
||||||
launchIO {
|
launchIO {
|
||||||
val chapters = if (manga.source == MERGED_SOURCE_ID) {
|
val chapters = if (manga.source == MERGED_SOURCE_ID) {
|
||||||
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.toDomainManga()!!)
|
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.id!!)
|
||||||
} else {
|
} else {
|
||||||
db.getChapters(manga).executeAsBlocking()
|
db.getChapters(manga).executeAsBlocking()
|
||||||
}
|
}
|
||||||
@ -820,7 +819,7 @@ class LibraryPresenter(
|
|||||||
/** Returns first unread chapter of a manga */
|
/** Returns first unread chapter of a manga */
|
||||||
fun getFirstUnread(manga: Manga): Chapter? {
|
fun getFirstUnread(manga: Manga): Chapter? {
|
||||||
val chapters = if (manga.source == MERGED_SOURCE_ID) {
|
val chapters = if (manga.source == MERGED_SOURCE_ID) {
|
||||||
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.toDomainManga()!!)
|
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.id!!)
|
||||||
} else db.getChapters(manga).executeAsBlocking()
|
} else db.getChapters(manga).executeAsBlocking()
|
||||||
return if (manga.isEhBasedManga()) {
|
return if (manga.isEhBasedManga()) {
|
||||||
val chapter = chapters.sortedBy { it.source_order }.getOrNull(0)
|
val chapter = chapters.sortedBy { it.source_order }.getOrNull(0)
|
||||||
|
@ -4,6 +4,9 @@ import android.content.Context
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -69,7 +72,9 @@ import kotlinx.coroutines.async
|
|||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -93,6 +98,8 @@ class MangaPresenter(
|
|||||||
private val downloadManager: DownloadManager = Injekt.get(),
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val coverCache: CoverCache = Injekt.get(),
|
private val coverCache: CoverCache = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
|
private val getMergedChapterByMangaId: GetMergedChapterByMangaId = Injekt.get(),
|
||||||
) : BasePresenter<MangaController>() {
|
) : BasePresenter<MangaController>() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,9 +115,7 @@ class MangaPresenter(
|
|||||||
/**
|
/**
|
||||||
* Subject of list of chapters to allow updating the view without going to DB.
|
* Subject of list of chapters to allow updating the view without going to DB.
|
||||||
*/
|
*/
|
||||||
private val chaptersRelay: PublishRelay<List<ChapterItem>> by lazy {
|
private val chaptersRelay by lazy { PublishRelay.create<List<ChapterItem>>() }
|
||||||
PublishRelay.create<List<ChapterItem>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the chapter list has been requested to the source.
|
* Whether the chapter list has been requested to the source.
|
||||||
@ -220,52 +225,48 @@ class MangaPresenter(
|
|||||||
|
|
||||||
// Chapters list - start
|
// Chapters list - start
|
||||||
|
|
||||||
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
|
// Keeps subscribed to changes and sends the list of chapters to the relay.
|
||||||
// changes, and sends the list of chapters to the relay.
|
presenterScope.launchIO {
|
||||||
add(
|
manga.id?.let { mangaId ->
|
||||||
(/* SY --> */if (source is MergedSource) source.getChaptersObservable(manga.toDomainManga()!!, true, dedupe) else /* SY <-- */ db.getChapters(manga).asRxObservable())
|
if (source is MergedSource) {
|
||||||
.map { chapters ->
|
getMergedChapterByMangaId.subscribe(mangaId)
|
||||||
// Convert every chapter to a model.
|
.map { source.transformMergedChapters(mangaId, it, true, dedupe) }
|
||||||
chapters.map { it.toModel() }
|
} else {
|
||||||
|
getChapterByMangaId.subscribe(mangaId)
|
||||||
}
|
}
|
||||||
.doOnNext { chapters ->
|
.collectLatest { domainChapters ->
|
||||||
// Find downloaded chapters
|
val chapterItems = domainChapters.map { it.toDbChapter().toModel() }
|
||||||
setDownloadedChapters(chapters)
|
setDownloadedChapters(chapterItems)
|
||||||
|
this@MangaPresenter.allChapters = chapterItems
|
||||||
|
observeDownloads()
|
||||||
|
|
||||||
allChapterScanlators = chapters.flatMap { MdUtil.getScanlators(it.chapter.scanlator) }.toSet()
|
// SY -->
|
||||||
|
if (domainChapters.isNotEmpty() && (source.isEhBasedSource()) && DebugToggles.ENABLE_EXH_ROOT_REDIRECT.enabled) {
|
||||||
// Store the last emission
|
// Check for gallery in library and accept manga with lowest id
|
||||||
this.allChapters = chapters
|
// Find chapters sharing same root
|
||||||
|
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, domainChapters.map { it.toDbChapter() })
|
||||||
// Listen for download status changes
|
.onEach { (acceptedChain, _) ->
|
||||||
observeDownloads()
|
// Redirect if we are not the accepted root
|
||||||
|
if (manga.id != acceptedChain.manga.id && acceptedChain.manga.favorite) {
|
||||||
// SY -->
|
// Update if any of our chapters are not in accepted manga's chapters
|
||||||
if (chapters.isNotEmpty() && (source.isEhBasedSource()) && DebugToggles.ENABLE_EXH_ROOT_REDIRECT.enabled) {
|
xLogD("Found accepted manga %s", manga.url)
|
||||||
// Check for gallery in library and accept manga with lowest id
|
val ourChapterUrls = domainChapters.map { it.url }.toSet()
|
||||||
// Find chapters sharing same root
|
val acceptedChapterUrls = acceptedChain.chapters.map { it.url }.toSet()
|
||||||
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters)
|
val update = (ourChapterUrls - acceptedChapterUrls).isNotEmpty()
|
||||||
.onEach { (acceptedChain, _) ->
|
redirectFlow.emit(
|
||||||
// Redirect if we are not the accepted root
|
EXHRedirect(
|
||||||
if (manga.id != acceptedChain.manga.id && acceptedChain.manga.favorite) {
|
acceptedChain.manga,
|
||||||
// Update if any of our chapters are not in accepted manga's chapters
|
update,
|
||||||
xLogD("Found accepted manga %s", manga.url)
|
),
|
||||||
val ourChapterUrls = chapters.map { it.url }.toSet()
|
)
|
||||||
val acceptedChapterUrls = acceptedChain.chapters.map { it.url }.toSet()
|
}
|
||||||
val update = (ourChapterUrls - acceptedChapterUrls).isNotEmpty()
|
}.launchIn(presenterScope)
|
||||||
redirectFlow.emit(
|
}
|
||||||
EXHRedirect(
|
// SY <--
|
||||||
acceptedChain.manga,
|
chaptersRelay.call(chapterItems)
|
||||||
update,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.launchIn(presenterScope)
|
|
||||||
}
|
}
|
||||||
// SY <--
|
}
|
||||||
}
|
}
|
||||||
.subscribe { chaptersRelay.call(it) },
|
|
||||||
)
|
|
||||||
|
|
||||||
// Chapters list - end
|
// Chapters list - end
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.data.cache.CoverCache
|
|||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.saver.Image
|
import eu.kanade.tachiyomi.data.saver.Image
|
||||||
@ -146,7 +145,7 @@ class ReaderPresenter(
|
|||||||
// SY <--
|
// SY <--
|
||||||
val dbChapters = /* SY --> */ if (manga.source == MERGED_SOURCE_ID) {
|
val dbChapters = /* SY --> */ if (manga.source == MERGED_SOURCE_ID) {
|
||||||
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource)
|
(sourceManager.get(MERGED_SOURCE_ID) as MergedSource)
|
||||||
.getChaptersAsBlocking(manga.toDomainManga()!!)
|
.getChaptersAsBlocking(manga.id!!)
|
||||||
} else /* SY <-- */ db.getChapters(manga).executeAsBlocking()
|
} else /* SY <-- */ db.getChapters(manga).executeAsBlocking()
|
||||||
|
|
||||||
val selectedChapter = dbChapters.find { it.id == chapterId }
|
val selectedChapter = dbChapters.find { it.id == chapterId }
|
||||||
|
@ -23,11 +23,19 @@ SELECT *
|
|||||||
FROM chapters
|
FROM chapters
|
||||||
WHERE _id = :id;
|
WHERE _id = :id;
|
||||||
|
|
||||||
getChapterByMangaId:
|
getChaptersByMangaId:
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM chapters
|
FROM chapters
|
||||||
WHERE manga_id = :mangaId;
|
WHERE manga_id = :mangaId;
|
||||||
|
|
||||||
|
getMergedChaptersByMangaId:
|
||||||
|
SELECT chapters.*
|
||||||
|
FROM (
|
||||||
|
SELECT manga_id FROM merged WHERE merge_id = ?
|
||||||
|
) AS M
|
||||||
|
JOIN chapters
|
||||||
|
ON chapters.manga_id = M.manga_id;
|
||||||
|
|
||||||
removeChaptersWithIds:
|
removeChaptersWithIds:
|
||||||
DELETE FROM chapters
|
DELETE FROM chapters
|
||||||
WHERE _id IN :chapterIds;
|
WHERE _id IN :chapterIds;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user