From b96686e6ad0b46a586958179e8cbb1d6a9182323 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 12 Jun 2022 21:23:41 +0600 Subject: [PATCH] Fix chapter list live update (#7296) --- .../data/chapter/ChapterRepositoryImpl.kt | 12 +++--- .../data/history/HistoryRepositoryImpl.kt | 2 +- .../java/eu/kanade/domain/DomainModule.kt | 2 + .../chapter/interactor/GetChapterByMangaId.kt | 31 ++++++++++++++ .../interactor/SyncChaptersWithSource.kt | 3 +- .../chapter/repository/ChapterRepository.kt | 3 ++ .../tachiyomi/ui/manga/MangaPresenter.kt | 41 ++++++++----------- app/src/main/sqldelight/data/chapters.sq | 2 +- 8 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapterByMangaId.kt diff --git a/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt index 58fb236cc..5caaf9846 100644 --- a/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt @@ -6,6 +6,7 @@ import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.ChapterUpdate import eu.kanade.domain.chapter.repository.ChapterRepository import eu.kanade.tachiyomi.util.system.logcat +import kotlinx.coroutines.flow.Flow import logcat.LogPriority class ChapterRepositoryImpl( @@ -96,11 +97,10 @@ class ChapterRepositoryImpl( } override suspend fun getChapterByMangaId(mangaId: Long): List { - return try { - handler.awaitList { chaptersQueries.getChapterByMangaId(mangaId, chapterMapper) } - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) - emptyList() - } + return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } + } + + override suspend fun getChapterByMangaIdFlow(mangaId: Long): Flow> { + return handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } } } diff --git a/app/src/main/java/eu/kanade/data/history/HistoryRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/history/HistoryRepositoryImpl.kt index adf023120..4fa59901f 100644 --- a/app/src/main/java/eu/kanade/data/history/HistoryRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/history/HistoryRepositoryImpl.kt @@ -47,7 +47,7 @@ class HistoryRepositoryImpl( else -> throw NotImplementedError("Unknown sorting method") } - val chapters = handler.awaitList { chaptersQueries.getChapterByMangaId(mangaId, chapterMapper) } + val chapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } .sortedWith(sortFunction) val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id } diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 9be7f13d2..4af894e6b 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -4,6 +4,7 @@ import eu.kanade.data.chapter.ChapterRepositoryImpl import eu.kanade.data.history.HistoryRepositoryImpl import eu.kanade.data.manga.MangaRepositoryImpl import eu.kanade.data.source.SourceRepositoryImpl +import eu.kanade.domain.chapter.interactor.GetChapterByMangaId import eu.kanade.domain.chapter.interactor.ShouldUpdateDbChapter import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.UpdateChapter @@ -50,6 +51,7 @@ class DomainModule : InjektModule { addFactory { UpdateManga(get()) } addSingletonFactory { ChapterRepositoryImpl(get()) } + addFactory { GetChapterByMangaId(get()) } addFactory { UpdateChapter(get()) } addFactory { ShouldUpdateDbChapter() } addFactory { SyncChaptersWithSource(get(), get(), get(), get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapterByMangaId.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapterByMangaId.kt new file mode 100644 index 000000000..6e8db7510 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapterByMangaId.kt @@ -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 { + return try { + chapterRepository.getChapterByMangaId(mangaId) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + emptyList() + } + } + + suspend fun subscribe(mangaId: Long): Flow> { + return try { + chapterRepository.getChapterByMangaIdFlow(mangaId) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + flowOf(emptyList()) + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index 51029fd0b..23a1572f5 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -25,6 +25,7 @@ class SyncChaptersWithSource( private val chapterRepository: ChapterRepository = Injekt.get(), private val shouldUpdateDbChapter: ShouldUpdateDbChapter = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), + private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), ) { suspend fun await( @@ -45,7 +46,7 @@ class SyncChaptersWithSource( } // Chapters from db. - val dbChapters = chapterRepository.getChapterByMangaId(manga.id) + val dbChapters = getChapterByMangaId.await(manga.id) // Chapters from the source not in db. val toAdd = mutableListOf() diff --git a/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt b/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt index 9ffa37260..9f785d285 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.chapter.repository import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.ChapterUpdate +import kotlinx.coroutines.flow.Flow interface ChapterRepository { @@ -14,4 +15,6 @@ interface ChapterRepository { suspend fun removeChaptersWithIds(chapterIds: List) suspend fun getChapterByMangaId(mangaId: Long): List + + suspend fun getChapterByMangaIdFlow(mangaId: Long): Flow> } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 55563488e..07285ce5b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -4,6 +4,8 @@ import android.content.Context import android.net.Uri import android.os.Bundle import com.jakewharton.rxrelay.PublishRelay +import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category @@ -44,6 +46,7 @@ import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Stat import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.supervisorScope import logcat.LogPriority import rx.Observable @@ -63,6 +66,7 @@ class MangaPresenter( private val trackManager: TrackManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val coverCache: CoverCache = Injekt.get(), + private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), ) : BasePresenter() { /** @@ -78,9 +82,7 @@ class MangaPresenter( /** * Subject of list of chapters to allow updating the view without going to DB. */ - private val chaptersRelay: PublishRelay> by lazy { - PublishRelay.create>() - } + private val chaptersRelay by lazy { PublishRelay.create>() } /** * Whether the chapter list has been requested to the source. @@ -144,26 +146,19 @@ class MangaPresenter( // Chapters list - start - // Add the subscription that retrieves the chapters from the database, keeps subscribed to - // changes, and sends the list of chapters to the relay. - add( - db.getChapters(manga).asRxObservable() - .map { chapters -> - // Convert every chapter to a model. - chapters.map { it.toModel() } - } - .doOnNext { chapters -> - // Find downloaded chapters - setDownloadedChapters(chapters) - - // Store the last emission - this.allChapters = chapters - - // Listen for download status changes - observeDownloads() - } - .subscribe { chaptersRelay.call(it) }, - ) + // Keeps subscribed to changes and sends the list of chapters to the relay. + presenterScope.launchIO { + manga.id?.let { mangaId -> + getChapterByMangaId.subscribe(mangaId) + .collectLatest { domainChapters -> + val chapterItems = domainChapters.map { it.toDbChapter().toModel() } + setDownloadedChapters(chapterItems) + this@MangaPresenter.allChapters = chapterItems + observeDownloads() + chaptersRelay.call(chapterItems) + } + } + } // Chapters list - end diff --git a/app/src/main/sqldelight/data/chapters.sq b/app/src/main/sqldelight/data/chapters.sq index c7d8634a5..dd71cc863 100644 --- a/app/src/main/sqldelight/data/chapters.sq +++ b/app/src/main/sqldelight/data/chapters.sq @@ -23,7 +23,7 @@ SELECT * FROM chapters WHERE _id = :id; -getChapterByMangaId: +getChaptersByMangaId: SELECT * FROM chapters WHERE manga_id = :mangaId;