mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Replace some usages of RxJava
This commit is contained in:
		| @@ -1,10 +1,12 @@ | ||||
| package eu.kanade.tachiyomi.data.download.model | ||||
|  | ||||
| import com.jakewharton.rxrelay.PublishRelay | ||||
| import eu.kanade.core.util.asFlow | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.download.DownloadStore | ||||
| import eu.kanade.tachiyomi.source.model.Page | ||||
| import kotlinx.coroutines.flow.Flow | ||||
| import rx.Observable | ||||
| import rx.subjects.PublishSubject | ||||
| import java.util.concurrent.CopyOnWriteArrayList | ||||
| @@ -72,8 +74,11 @@ class DownloadQueue( | ||||
|     fun getActiveDownloads(): Observable<Download> = | ||||
|         Observable.from(this).filter { download -> download.status == Download.State.DOWNLOADING } | ||||
|  | ||||
|     @Deprecated("Use getStatusAsFlow instead") | ||||
|     fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer() | ||||
|  | ||||
|     fun getStatusAsFlow(): Flow<Download> = getStatusObservable().asFlow() | ||||
|  | ||||
|     fun getUpdatedObservable(): Observable<List<Download>> = updatedRelay.onBackpressureBuffer() | ||||
|         .startWith(Unit) | ||||
|         .map { this } | ||||
| @@ -84,6 +89,7 @@ class DownloadQueue( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Deprecated("Use getProgressAsFlow instead") | ||||
|     fun getProgressObservable(): Observable<Download> { | ||||
|         return statusSubject.onBackpressureBuffer() | ||||
|             .startWith(getActiveDownloads()) | ||||
| @@ -103,6 +109,10 @@ class DownloadQueue( | ||||
|             .filter { it.status == Download.State.DOWNLOADING } | ||||
|     } | ||||
|  | ||||
|     fun getProgressAsFlow(): Flow<Download> { | ||||
|         return getProgressObservable().asFlow() | ||||
|     } | ||||
|  | ||||
|     private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) { | ||||
|         pages?.forEach { it.setStatusSubject(subject) } | ||||
|     } | ||||
|   | ||||
| @@ -57,13 +57,4 @@ open class BasePresenter<V> : RxPresenter<V>() { | ||||
|      * @param onError function to execute when the observable throws an error. | ||||
|      */ | ||||
|     fun <T> Observable<T>.subscribeLatestCache(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverLatestCache<T>()).subscribe(split(onNext, onError)).apply { add(this) } | ||||
|  | ||||
|     /** | ||||
|      * Subscribes an observable with [deliverReplay] and adds it to the presenter's lifecycle | ||||
|      * subscription list. | ||||
|      * | ||||
|      * @param onNext function to execute when the observable emits an item. | ||||
|      * @param onError function to execute when the observable throws an error. | ||||
|      */ | ||||
|     fun <T> Observable<T>.subscribeReplay(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverReplay<T>()).subscribe(split(onNext, onError)).apply { add(this) } | ||||
| } | ||||
|   | ||||
| @@ -51,15 +51,13 @@ import kotlinx.coroutines.Job | ||||
| import kotlinx.coroutines.flow.asFlow | ||||
| import kotlinx.coroutines.flow.catch | ||||
| import kotlinx.coroutines.flow.collect | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import kotlinx.coroutines.flow.filter | ||||
| import kotlinx.coroutines.flow.firstOrNull | ||||
| import kotlinx.coroutines.flow.map | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import logcat.LogPriority | ||||
| import rx.Subscription | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.util.Date | ||||
| @@ -112,7 +110,7 @@ open class BrowseSourcePresenter( | ||||
|     /** | ||||
|      * Subscription for the pager. | ||||
|      */ | ||||
|     private var pagerSubscription: Subscription? = null | ||||
|     private var pagerJob: Job? = null | ||||
|  | ||||
|     /** | ||||
|      * Subscription for one request from the pager. | ||||
| @@ -129,7 +127,6 @@ open class BrowseSourcePresenter( | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         source = sourceManager.get(sourceId) as? CatalogueSource ?: return | ||||
|  | ||||
|         sourceFilters = source.getFilterList() | ||||
|  | ||||
|         if (savedState != null) { | ||||
| @@ -158,25 +155,37 @@ open class BrowseSourcePresenter( | ||||
|         pager = createPager(query, filters) | ||||
|  | ||||
|         val sourceId = source.id | ||||
|  | ||||
|         val sourceDisplayMode = prefs.sourceDisplayMode() | ||||
|  | ||||
|         // Prepare the pager. | ||||
|         pagerSubscription?.let { remove(it) } | ||||
|         pagerSubscription = pager.results() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .map { (first, second) -> first to second.map { networkToLocalManga(it, sourceId).toDomainManga()!! } } | ||||
|             .doOnNext { initializeMangas(it.second) } | ||||
|             .map { (first, second) -> first to second.map { SourceItem(it, sourceDisplayMode) } } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeReplay( | ||||
|                 { view, (page, mangas) -> | ||||
|                     view.onAddPage(page, mangas) | ||||
|                 }, | ||||
|                 { _, error -> | ||||
|         pagerJob?.cancel() | ||||
|         pagerJob = presenterScope.launchIO { | ||||
|             pager.asFlow() | ||||
|                 .map { (first, second) -> | ||||
|                     first to second.map { | ||||
|                         networkToLocalManga( | ||||
|                             it, | ||||
|                             sourceId, | ||||
|                         ).toDomainManga()!! | ||||
|                     } | ||||
|                 } | ||||
|                 .onEach { initializeMangas(it.second) } | ||||
|                 .map { (first, second) -> | ||||
|                     first to second.map { | ||||
|                         SourceItem( | ||||
|                             it, | ||||
|                             sourceDisplayMode, | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|                 .catch { error -> | ||||
|                     logcat(LogPriority.ERROR, error) | ||||
|                 }, | ||||
|             ) | ||||
|                 } | ||||
|                 .collectLatest { (page, mangas) -> | ||||
|                     withUIContext { | ||||
|                         view?.onAddPage(page, mangas) | ||||
|                     } | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|         // Request first page. | ||||
|         requestNext() | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.browse.source.browse | ||||
|  | ||||
| import com.jakewharton.rxrelay.PublishRelay | ||||
| import eu.kanade.core.util.asFlow | ||||
| import eu.kanade.tachiyomi.source.model.MangasPage | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import rx.Observable | ||||
| import kotlinx.coroutines.flow.Flow | ||||
|  | ||||
| /** | ||||
|  * A general pager for source requests (latest updates, popular, search) | ||||
| @@ -15,8 +16,8 @@ abstract class Pager(var currentPage: Int = 1) { | ||||
|  | ||||
|     protected val results: PublishRelay<Pair<Int, List<SManga>>> = PublishRelay.create() | ||||
|  | ||||
|     fun results(): Observable<Pair<Int, List<SManga>>> { | ||||
|         return results.asObservable() | ||||
|     fun asFlow(): Flow<Pair<Int, List<SManga>>> { | ||||
|         return results.asObservable().asFlow() | ||||
|     } | ||||
|  | ||||
|     abstract suspend fun requestNextPage() | ||||
|   | ||||
| @@ -59,6 +59,7 @@ import kotlinx.coroutines.flow.MutableStateFlow | ||||
| import kotlinx.coroutines.flow.asStateFlow | ||||
| import kotlinx.coroutines.flow.catch | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import kotlinx.coroutines.flow.filter | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.map | ||||
| import kotlinx.coroutines.flow.update | ||||
| @@ -66,9 +67,6 @@ import kotlinx.coroutines.runBlocking | ||||
| import kotlinx.coroutines.supervisorScope | ||||
| import kotlinx.coroutines.withContext | ||||
| import logcat.LogPriority | ||||
| import rx.Subscription | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.text.DateFormat | ||||
| @@ -119,8 +117,8 @@ class MangaPresenter( | ||||
|     /** | ||||
|      * Subscription to observe download status changes. | ||||
|      */ | ||||
|     private var observeDownloadsStatusSubscription: Subscription? = null | ||||
|     private var observeDownloadsPageSubscription: Subscription? = null | ||||
|     private var observeDownloadsStatusJob: Job? = null | ||||
|     private var observeDownloadsPageJob: Job? = null | ||||
|  | ||||
|     private var _trackList: List<TrackItem> = emptyList() | ||||
|     val trackList get() = _trackList | ||||
| @@ -401,29 +399,29 @@ class MangaPresenter( | ||||
|     // Chapters list - start | ||||
|  | ||||
|     private fun observeDownloads() { | ||||
|         observeDownloadsStatusSubscription?.let { remove(it) } | ||||
|         observeDownloadsStatusSubscription = downloadManager.queue.getStatusObservable() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .onBackpressureBuffer() | ||||
|             .filter { download -> download.manga.id == successState?.manga?.id } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeLatestCache( | ||||
|                 { _, it -> updateDownloadState(it) }, | ||||
|                 { _, error -> | ||||
|                     logcat(LogPriority.ERROR, error) | ||||
|                 }, | ||||
|             ) | ||||
|         observeDownloadsStatusJob?.cancel() | ||||
|         observeDownloadsStatusJob = presenterScope.launchIO { | ||||
|             downloadManager.queue.getStatusAsFlow() | ||||
|                 .filter { it.manga.id == successState?.manga?.id } | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .collectLatest { | ||||
|                     withUIContext { | ||||
|                         updateDownloadState(it) | ||||
|                     } | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|         observeDownloadsPageSubscription?.let { remove(it) } | ||||
|         observeDownloadsPageSubscription = downloadManager.queue.getProgressObservable() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .onBackpressureBuffer() | ||||
|             .filter { download -> download.manga.id == successState?.manga?.id } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeLatestCache( | ||||
|                 { _, download -> updateDownloadState(download) }, | ||||
|                 { _, error -> logcat(LogPriority.ERROR, error) }, | ||||
|             ) | ||||
|         observeDownloadsPageJob?.cancel() | ||||
|         observeDownloadsPageJob = presenterScope.launchIO { | ||||
|             downloadManager.queue.getProgressAsFlow() | ||||
|                 .filter { it.manga.id == successState?.manga?.id } | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .collectLatest { | ||||
|                     withUIContext { | ||||
|                         updateDownloadState(it) | ||||
|                     } | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun updateDownloadState(download: Download) { | ||||
|   | ||||
| @@ -17,31 +17,30 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter | ||||
| import eu.kanade.tachiyomi.ui.recent.DateSectionItem | ||||
| import eu.kanade.tachiyomi.util.lang.launchIO | ||||
| import eu.kanade.tachiyomi.util.lang.toDateKey | ||||
| import eu.kanade.tachiyomi.util.lang.withUIContext | ||||
| import eu.kanade.tachiyomi.util.system.logcat | ||||
| import kotlinx.coroutines.flow.MutableStateFlow | ||||
| import kotlinx.coroutines.flow.StateFlow | ||||
| import kotlinx.coroutines.flow.asStateFlow | ||||
| import kotlinx.coroutines.flow.catch | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import kotlinx.coroutines.flow.map | ||||
| import logcat.LogPriority | ||||
| import rx.Observable | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.text.DateFormat | ||||
| import java.util.Calendar | ||||
| import java.util.Date | ||||
| import java.util.TreeMap | ||||
|  | ||||
| class UpdatesPresenter : BasePresenter<UpdatesController>() { | ||||
|  | ||||
|     val preferences: PreferencesHelper by injectLazy() | ||||
|     private val downloadManager: DownloadManager by injectLazy() | ||||
|     private val sourceManager: SourceManager by injectLazy() | ||||
|  | ||||
|     private val handler: DatabaseHandler by injectLazy() | ||||
|     private val updateChapter: UpdateChapter by injectLazy() | ||||
|     private val setReadStatus: SetReadStatus by injectLazy() | ||||
| class UpdatesPresenter( | ||||
|     private val preferences: PreferencesHelper = Injekt.get(), | ||||
|     private val downloadManager: DownloadManager = Injekt.get(), | ||||
|     private val sourceManager: SourceManager = Injekt.get(), | ||||
|     private val handler: DatabaseHandler = Injekt.get(), | ||||
|     private val updateChapter: UpdateChapter = Injekt.get(), | ||||
|     private val setReadStatus: SetReadStatus = Injekt.get(), | ||||
| ) : BasePresenter<UpdatesController>() { | ||||
|  | ||||
|     private val relativeTime: Int = preferences.relativeTime().get() | ||||
|     private val dateFormat: DateFormat = preferences.dateFormat() | ||||
| @@ -52,77 +51,70 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() { | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         getUpdatesObservable() | ||||
|         presenterScope.launchIO { | ||||
|             subscribeToUpdates() | ||||
|  | ||||
|         downloadManager.queue.getStatusObservable() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .onBackpressureBuffer() | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeLatestCache( | ||||
|                 { view, it -> | ||||
|                     onDownloadStatusChange(it) | ||||
|                     view.onChapterDownloadUpdate(it) | ||||
|                 }, | ||||
|                 { _, error -> | ||||
|                     logcat(LogPriority.ERROR, error) | ||||
|                 }, | ||||
|             ) | ||||
|             downloadManager.queue.getStatusAsFlow() | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .collectLatest { | ||||
|                     withUIContext { | ||||
|                         onDownloadStatusChange(it) | ||||
|                         view?.onChapterDownloadUpdate(it) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|         downloadManager.queue.getProgressObservable() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .onBackpressureBuffer() | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeLatestCache(UpdatesController::onChapterDownloadUpdate) { _, error -> | ||||
|                 logcat(LogPriority.ERROR, error) | ||||
|             } | ||||
|             downloadManager.queue.getProgressAsFlow() | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .collectLatest { | ||||
|                     withUIContext { | ||||
|                         view?.onChapterDownloadUpdate(it) | ||||
|                     } | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get observable containing recent chapters and date | ||||
|      * | ||||
|      * @return observable containing recent chapters and date | ||||
|      */ | ||||
|     private fun getUpdatesObservable() { | ||||
|     private suspend fun subscribeToUpdates() { | ||||
|         // Set date limit for recent chapters | ||||
|         presenterScope.launchIO { | ||||
|             val cal = Calendar.getInstance().apply { | ||||
|                 time = Date() | ||||
|                 add(Calendar.MONTH, -3) | ||||
|             } | ||||
|  | ||||
|             handler | ||||
|                 .subscribeToList { | ||||
|                     mangasQueries.getRecentlyUpdated(after = cal.timeInMillis, mangaChapterMapper) | ||||
|                 } | ||||
|                 .map { mangaChapter -> | ||||
|                     val map = TreeMap<Date, MutableList<Pair<Manga, Chapter>>> { d1, d2 -> d2.compareTo(d1) } | ||||
|                     val byDate = mangaChapter.groupByTo(map) { it.second.dateFetch.toDateKey() } | ||||
|                     byDate.flatMap { entry -> | ||||
|                         val dateItem = DateSectionItem(entry.key, relativeTime, dateFormat) | ||||
|                         entry.value | ||||
|                             .sortedWith(compareBy({ it.second.dateFetch }, { it.second.chapterNumber })).asReversed() | ||||
|                             .map { UpdatesItem(it.second, it.first, dateItem) } | ||||
|                     } | ||||
|                 } | ||||
|                 .collectLatest { list -> | ||||
|                     list.forEach { item -> | ||||
|                         // Find an active download for this chapter. | ||||
|                         val download = downloadManager.queue.find { it.chapter.id == item.chapter.id } | ||||
|  | ||||
|                         // If there's an active download, assign it, otherwise ask the manager if | ||||
|                         // the chapter is downloaded and assign it to the status. | ||||
|                         if (download != null) { | ||||
|                             item.download = download | ||||
|                         } | ||||
|                     } | ||||
|                     setDownloadedChapters(list) | ||||
|  | ||||
|                     _updates.value = list | ||||
|  | ||||
|                     // Set unread chapter count for bottom bar badge | ||||
|                     preferences.unreadUpdatesCount().set(list.count { !it.chapter.read }) | ||||
|                 } | ||||
|         val cal = Calendar.getInstance().apply { | ||||
|             time = Date() | ||||
|             add(Calendar.MONTH, -3) | ||||
|         } | ||||
|  | ||||
|         handler | ||||
|             .subscribeToList { | ||||
|                 mangasQueries.getRecentlyUpdated(after = cal.timeInMillis, mangaChapterMapper) | ||||
|             } | ||||
|             .map { mangaChapter -> | ||||
|                 val map = TreeMap<Date, MutableList<Pair<Manga, Chapter>>> { d1, d2 -> d2.compareTo(d1) } | ||||
|                 val byDate = mangaChapter.groupByTo(map) { it.second.dateFetch.toDateKey() } | ||||
|                 byDate.flatMap { entry -> | ||||
|                     val dateItem = DateSectionItem(entry.key, relativeTime, dateFormat) | ||||
|                     entry.value | ||||
|                         .sortedWith(compareBy({ it.second.dateFetch }, { it.second.chapterNumber })).asReversed() | ||||
|                         .map { UpdatesItem(it.second, it.first, dateItem) } | ||||
|                 } | ||||
|             } | ||||
|             .collectLatest { list -> | ||||
|                 list.forEach { item -> | ||||
|                     // Find an active download for this chapter. | ||||
|                     val download = downloadManager.queue.find { it.chapter.id == item.chapter.id } | ||||
|  | ||||
|                     // If there's an active download, assign it, otherwise ask the manager if | ||||
|                     // the chapter is downloaded and assign it to the status. | ||||
|                     if (download != null) { | ||||
|                         item.download = download | ||||
|                     } | ||||
|                 } | ||||
|                 setDownloadedChapters(list) | ||||
|  | ||||
|                 _updates.value = list | ||||
|  | ||||
|                 // Set unread chapter count for bottom bar badge | ||||
|                 preferences.unreadUpdatesCount().set(list.count { !it.chapter.read }) | ||||
|             } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -184,16 +176,14 @@ class UpdatesPresenter : BasePresenter<UpdatesController>() { | ||||
|      * @param chapters list of chapters | ||||
|      */ | ||||
|     fun deleteChapters(chapters: List<UpdatesItem>) { | ||||
|         Observable.just(chapters) | ||||
|             .doOnNext { deleteChaptersInternal(it) } | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeFirst( | ||||
|                 { view, _ -> | ||||
|                     view.onChaptersDeleted() | ||||
|                 }, | ||||
|                 UpdatesController::onChaptersDeletedError, | ||||
|             ) | ||||
|         launchIO { | ||||
|             try { | ||||
|                 deleteChaptersInternal(chapters) | ||||
|                 withUIContext { view?.onChaptersDeleted() } | ||||
|             } catch (e: Throwable) { | ||||
|                 withUIContext { view?.onChaptersDeletedError(e) } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user