Cleanup Page status (#8696)

* Cleanup Page statusSubject and statusCallback

* Convert Page status from Int to enum
This commit is contained in:
Two-Ai 2022-12-07 18:28:38 -05:00 committed by GitHub
parent f05e251991
commit 6ca32710be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 74 additions and 90 deletions

View file

@ -179,7 +179,7 @@ class DownloadManager(
files.sortedBy { it.name } files.sortedBy { it.name }
.mapIndexed { i, file -> .mapIndexed { i, file ->
Page(i, uri = file.uri).apply { status = Page.READY } Page(i, uri = file.uri).apply { status = Page.State.READY }
} }
} }
} }

View file

@ -402,13 +402,13 @@ class Downloader(
page.uri = file.uri page.uri = file.uri
page.progress = 100 page.progress = 100
download.downloadedImages++ download.downloadedImages++
page.status = Page.READY page.status = Page.State.READY
} }
.map { page } .map { page }
// Mark this page as error and allow to download the remaining // Mark this page as error and allow to download the remaining
.onErrorReturn { .onErrorReturn {
page.progress = 0 page.progress = 0
page.status = Page.ERROR page.status = Page.State.ERROR
notifier.onError(it.message, download.chapter.name, download.manga.title) notifier.onError(it.message, download.chapter.name, download.manga.title)
page page
} }
@ -423,7 +423,7 @@ class Downloader(
* @param filename the filename of the image. * @param filename the filename of the image.
*/ */
private fun downloadImage(page: Page, source: HttpSource, tmpDir: UniFile, filename: String): Observable<UniFile> { private fun downloadImage(page: Page, source: HttpSource, tmpDir: UniFile, filename: String): Observable<UniFile> {
page.status = Page.DOWNLOAD_IMAGE page.status = Page.State.DOWNLOAD_IMAGE
page.progress = 0 page.progress = 0
return source.fetchImage(page) return source.fetchImage(page)
.map { response -> .map { response ->

View file

@ -100,11 +100,11 @@ class DownloadQueue(
.startWith(getActiveDownloads()) .startWith(getActiveDownloads())
.flatMap { download -> .flatMap { download ->
if (download.status == Download.State.DOWNLOADING) { if (download.status == Download.State.DOWNLOADING) {
val pageStatusSubject = PublishSubject.create<Int>() val pageStatusSubject = PublishSubject.create<Page.State>()
setPagesSubject(download.pages, pageStatusSubject) setPagesSubject(download.pages, pageStatusSubject)
return@flatMap pageStatusSubject return@flatMap pageStatusSubject
.onBackpressureBuffer() .onBackpressureBuffer()
.filter { it == Page.READY } .filter { it == Page.State.READY }
.map { download } .map { download }
} else if (download.status == Download.State.DOWNLOADED || download.status == Download.State.ERROR) { } else if (download.status == Download.State.DOWNLOADED || download.status == Download.State.ERROR) {
setPagesSubject(download.pages, null) setPagesSubject(download.pages, null)
@ -120,7 +120,7 @@ class DownloadQueue(
} }
} }
private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) { private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Page.State>?) {
pages?.forEach { it.setStatusSubject(subject) } pages?.forEach { it.statusSubject = subject }
} }
} }

View file

@ -33,7 +33,7 @@ class ReaderPageSheet(
* Sets the image of this page as the cover of the manga. * Sets the image of this page as the cover of the manga.
*/ */
private fun setAsCover() { private fun setAsCover() {
if (page.status != Page.READY) return if (page.status != Page.State.READY) return
MaterialAlertDialogBuilder(activity) MaterialAlertDialogBuilder(activity)
.setMessage(R.string.confirm_set_image_as_cover) .setMessage(R.string.confirm_set_image_as_cover)

View file

@ -720,7 +720,7 @@ class ReaderPresenter(
* There's also a notification to allow sharing the image somewhere else or deleting it. * There's also a notification to allow sharing the image somewhere else or deleting it.
*/ */
fun saveImage(page: ReaderPage) { fun saveImage(page: ReaderPage) {
if (page.status != Page.READY) return if (page.status != Page.State.READY) return
val manga = manga ?: return val manga = manga ?: return
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
@ -761,7 +761,7 @@ class ReaderPresenter(
* image will be kept so it won't be taking lots of internal disk space. * image will be kept so it won't be taking lots of internal disk space.
*/ */
fun shareImage(page: ReaderPage) { fun shareImage(page: ReaderPage) {
if (page.status != Page.READY) return if (page.status != Page.State.READY) return
val manga = manga ?: return val manga = manga ?: return
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
@ -792,7 +792,7 @@ class ReaderPresenter(
* Sets the image of this [page] as cover and notifies the UI of the result. * Sets the image of this [page] as cover and notifies the UI of the result.
*/ */
fun setAsCover(context: Context, page: ReaderPage) { fun setAsCover(context: Context, page: ReaderPage) {
if (page.status != Page.READY) return if (page.status != Page.State.READY) return
val manga = manga?.toDomainManga() ?: return val manga = manga?.toDomainManga() ?: return
val stream = page.stream ?: return val stream = page.stream ?: return

View file

@ -25,7 +25,7 @@ class DirectoryPageLoader(val file: File) : PageLoader() {
val streamFn = { FileInputStream(file) } val streamFn = { FileInputStream(file) }
ReaderPage(i).apply { ReaderPage(i).apply {
stream = streamFn stream = streamFn
status = Page.READY status = Page.State.READY
} }
} }
.let { Observable.just(it) } .let { Observable.just(it) }
@ -34,7 +34,7 @@ class DirectoryPageLoader(val file: File) : PageLoader() {
/** /**
* Returns an observable that emits a ready state. * Returns an observable that emits a ready state.
*/ */
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.just(Page.READY) return Observable.just(Page.State.READY)
} }
} }

View file

@ -54,13 +54,13 @@ class DownloadPageLoader(
ReaderPage(page.index, page.url, page.imageUrl) { ReaderPage(page.index, page.url, page.imageUrl) {
context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!! context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!!
}.apply { }.apply {
status = Page.READY status = Page.State.READY
} }
} }
} }
} }
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.just(Page.READY) return Observable.just(Page.State.READY)
} }
} }

View file

@ -34,7 +34,7 @@ class EpubPageLoader(file: File) : PageLoader() {
val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } val streamFn = { epub.getInputStream(epub.getEntry(path)!!) }
ReaderPage(i).apply { ReaderPage(i).apply {
stream = streamFn stream = streamFn
status = Page.READY status = Page.State.READY
} }
} }
.let { Observable.just(it) } .let { Observable.just(it) }
@ -43,12 +43,12 @@ class EpubPageLoader(file: File) : PageLoader() {
/** /**
* Returns an observable that emits a ready state unless the loader was recycled. * Returns an observable that emits a ready state unless the loader was recycled.
*/ */
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.just( return Observable.just(
if (isRecycled) { if (isRecycled) {
Page.ERROR Page.State.ERROR
} else { } else {
Page.READY Page.State.READY
}, },
) )
} }

View file

@ -44,7 +44,7 @@ class HttpPageLoader(
init { init {
subscriptions += Observable.defer { Observable.just(queue.take().page) } subscriptions += Observable.defer { Observable.just(queue.take().page) }
.filter { it.status == Page.QUEUE } .filter { it.status == Page.State.QUEUE }
.concatMap { source.fetchImageFromCacheThenNet(it) } .concatMap { source.fetchImageFromCacheThenNet(it) }
.repeat() .repeat()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -101,25 +101,25 @@ class HttpPageLoader(
* Returns an observable that loads a page through the queue and listens to its result to * Returns an observable that loads a page through the queue and listens to its result to
* emit new states. It handles re-enqueueing pages if they were evicted from the cache. * emit new states. It handles re-enqueueing pages if they were evicted from the cache.
*/ */
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.defer { return Observable.defer {
val imageUrl = page.imageUrl val imageUrl = page.imageUrl
// Check if the image has been deleted // Check if the image has been deleted
if (page.status == Page.READY && imageUrl != null && !chapterCache.isImageInCache(imageUrl)) { if (page.status == Page.State.READY && imageUrl != null && !chapterCache.isImageInCache(imageUrl)) {
page.status = Page.QUEUE page.status = Page.State.QUEUE
} }
// Automatically retry failed pages when subscribed to this page // Automatically retry failed pages when subscribed to this page
if (page.status == Page.ERROR) { if (page.status == Page.State.ERROR) {
page.status = Page.QUEUE page.status = Page.State.QUEUE
} }
val statusSubject = SerializedSubject(PublishSubject.create<Int>()) val statusSubject = SerializedSubject(PublishSubject.create<Page.State>())
page.setStatusSubject(statusSubject) page.statusSubject = statusSubject
val queuedPages = mutableListOf<PriorityPage>() val queuedPages = mutableListOf<PriorityPage>()
if (page.status == Page.QUEUE) { if (page.status == Page.State.QUEUE) {
queuedPages += PriorityPage(page, 1).also { queue.offer(it) } queuedPages += PriorityPage(page, 1).also { queue.offer(it) }
} }
queuedPages += preloadNextPages(page, preloadSize) queuedPages += preloadNextPages(page, preloadSize)
@ -127,7 +127,7 @@ class HttpPageLoader(
statusSubject.startWith(page.status) statusSubject.startWith(page.status)
.doOnUnsubscribe { .doOnUnsubscribe {
queuedPages.forEach { queuedPages.forEach {
if (it.page.status == Page.QUEUE) { if (it.page.status == Page.State.QUEUE) {
queue.remove(it) queue.remove(it)
} }
} }
@ -149,7 +149,7 @@ class HttpPageLoader(
return pages return pages
.subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size)) .subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size))
.mapNotNull { .mapNotNull {
if (it.status == Page.QUEUE) { if (it.status == Page.State.QUEUE) {
PriorityPage(it, 0).apply { queue.offer(this) } PriorityPage(it, 0).apply { queue.offer(this) }
} else { } else {
null null
@ -161,8 +161,8 @@ class HttpPageLoader(
* Retries a page. This method is only called from user interaction on the viewer. * Retries a page. This method is only called from user interaction on the viewer.
*/ */
override fun retryPage(page: ReaderPage) { override fun retryPage(page: ReaderPage) {
if (page.status == Page.ERROR) { if (page.status == Page.State.ERROR) {
page.status = Page.QUEUE page.status = Page.State.QUEUE
} }
queue.offer(PriorityPage(page, 2)) queue.offer(PriorityPage(page, 2))
} }
@ -200,9 +200,9 @@ class HttpPageLoader(
} }
private fun HttpSource.getImageUrl(page: ReaderPage): Observable<ReaderPage> { private fun HttpSource.getImageUrl(page: ReaderPage): Observable<ReaderPage> {
page.status = Page.LOAD_PAGE page.status = Page.State.LOAD_PAGE
return fetchImageUrl(page) return fetchImageUrl(page)
.doOnError { page.status = Page.ERROR } .doOnError { page.status = Page.State.ERROR }
.onErrorReturn { null } .onErrorReturn { null }
.doOnNext { page.imageUrl = it } .doOnNext { page.imageUrl = it }
.map { page } .map { page }
@ -227,9 +227,9 @@ class HttpPageLoader(
} }
.doOnNext { .doOnNext {
page.stream = { chapterCache.getImageFile(imageUrl).inputStream() } page.stream = { chapterCache.getImageFile(imageUrl).inputStream() }
page.status = Page.READY page.status = Page.State.READY
} }
.doOnError { page.status = Page.ERROR } .doOnError { page.status = Page.State.ERROR }
.onErrorReturn { page } .onErrorReturn { page }
} }
@ -239,7 +239,7 @@ class HttpPageLoader(
* @param page the page. * @param page the page.
*/ */
private fun HttpSource.cacheImage(page: ReaderPage): Observable<ReaderPage> { private fun HttpSource.cacheImage(page: ReaderPage): Observable<ReaderPage> {
page.status = Page.DOWNLOAD_IMAGE page.status = Page.State.DOWNLOAD_IMAGE
return fetchImage(page) return fetchImage(page)
.doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) } .doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) }
.map { page } .map { page }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.reader.loader package eu.kanade.tachiyomi.ui.reader.loader
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import rx.Observable import rx.Observable
@ -32,10 +33,9 @@ abstract class PageLoader {
abstract fun getPages(): Observable<List<ReaderPage>> abstract fun getPages(): Observable<List<ReaderPage>>
/** /**
* Returns an observable that should inform of the progress of the page (see the Page class * Returns an observable that should inform of the progress of the page
* for the available states)
*/ */
abstract fun getPage(page: ReaderPage): Observable<Int> abstract fun getPage(page: ReaderPage): Observable<Page.State>
/** /**
* Retries the given [page] in case it failed to load. This method only makes sense when an * Retries the given [page] in case it failed to load. This method only makes sense when an

View file

@ -48,7 +48,7 @@ class RarPageLoader(file: File) : PageLoader() {
.mapIndexed { i, header -> .mapIndexed { i, header ->
ReaderPage(i).apply { ReaderPage(i).apply {
stream = { getStream(header) } stream = { getStream(header) }
status = Page.READY status = Page.State.READY
} }
} }
.let { Observable.just(it.toList()) } .let { Observable.just(it.toList()) }
@ -57,12 +57,12 @@ class RarPageLoader(file: File) : PageLoader() {
/** /**
* Returns an observable that emits a ready state unless the loader was recycled. * Returns an observable that emits a ready state unless the loader was recycled.
*/ */
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.just( return Observable.just(
if (isRecycled) { if (isRecycled) {
Page.ERROR Page.State.ERROR
} else { } else {
Page.READY Page.State.READY
}, },
) )
} }

View file

@ -43,7 +43,7 @@ class ZipPageLoader(file: File) : PageLoader() {
.mapIndexed { i, entry -> .mapIndexed { i, entry ->
ReaderPage(i).apply { ReaderPage(i).apply {
stream = { zip.getInputStream(entry) } stream = { zip.getInputStream(entry) }
status = Page.READY status = Page.State.READY
} }
} }
.let { Observable.just(it.toList()) } .let { Observable.just(it.toList()) }
@ -52,12 +52,12 @@ class ZipPageLoader(file: File) : PageLoader() {
/** /**
* Returns an observable that emits a ready state unless the loader was recycled. * Returns an observable that emits a ready state unless the loader was recycled.
*/ */
override fun getPage(page: ReaderPage): Observable<Int> { override fun getPage(page: ReaderPage): Observable<Page.State> {
return Observable.just( return Observable.just(
if (isRecycled) { if (isRecycled) {
Page.ERROR Page.State.ERROR
} else { } else {
Page.READY Page.State.READY
}, },
) )
} }

View file

@ -10,7 +10,7 @@ class StencilPage(
override var chapter: ReaderChapter = parent.chapter override var chapter: ReaderChapter = parent.chapter
init { init {
status = READY status = State.READY
stream = stencilStream stream = stencilStream
} }
} }

View file

@ -119,19 +119,19 @@ class PagerPageHolder(
* *
* @param status the new status of the page. * @param status the new status of the page.
*/ */
private fun processStatus(status: Int) { private fun processStatus(status: Page.State) {
when (status) { when (status) {
Page.QUEUE -> setQueued() Page.State.QUEUE -> setQueued()
Page.LOAD_PAGE -> setLoading() Page.State.LOAD_PAGE -> setLoading()
Page.DOWNLOAD_IMAGE -> { Page.State.DOWNLOAD_IMAGE -> {
observeProgress() observeProgress()
setDownloading() setDownloading()
} }
Page.READY -> { Page.State.READY -> {
setImage() setImage()
unsubscribeProgress() unsubscribeProgress()
} }
Page.ERROR -> { Page.State.ERROR -> {
setError() setError()
unsubscribeProgress() unsubscribeProgress()
} }

View file

@ -165,19 +165,19 @@ class WebtoonPageHolder(
* *
* @param status the new status of the page. * @param status the new status of the page.
*/ */
private fun processStatus(status: Int) { private fun processStatus(status: Page.State) {
when (status) { when (status) {
Page.QUEUE -> setQueued() Page.State.QUEUE -> setQueued()
Page.LOAD_PAGE -> setLoading() Page.State.LOAD_PAGE -> setLoading()
Page.DOWNLOAD_IMAGE -> { Page.State.DOWNLOAD_IMAGE -> {
observeProgress() observeProgress()
setDownloading() setDownloading()
} }
Page.READY -> { Page.State.READY -> {
setImage() setImage()
unsubscribeProgress() unsubscribeProgress()
} }
Page.ERROR -> { Page.State.ERROR -> {
setError() setError()
unsubscribeProgress() unsubscribeProgress()
} }

View file

@ -19,26 +19,18 @@ open class Page(
@Transient @Transient
@Volatile @Volatile
var status: Int = 0 var status: State = State.QUEUE
set(value) { set(value) {
field = value field = value
statusSubject?.onNext(value) statusSubject?.onNext(value)
statusCallback?.invoke(this)
} }
@Transient @Transient
@Volatile @Volatile
var progress: Int = 0 var progress: Int = 0
set(value) {
field = value
statusCallback?.invoke(this)
}
@Transient @Transient
private var statusSubject: Subject<Int, Int>? = null var statusSubject: Subject<State, State>? = null
@Transient
private var statusCallback: ((Page) -> Unit)? = null
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
progress = if (contentLength > 0) { progress = if (contentLength > 0) {
@ -48,19 +40,11 @@ open class Page(
} }
} }
fun setStatusSubject(subject: Subject<Int, Int>?) { enum class State {
this.statusSubject = subject QUEUE,
} LOAD_PAGE,
DOWNLOAD_IMAGE,
fun setStatusCallback(f: ((Page) -> Unit)?) { READY,
statusCallback = f ERROR,
}
companion object {
const val QUEUE = 0
const val LOAD_PAGE = 1
const val DOWNLOAD_IMAGE = 2
const val READY = 3
const val ERROR = 4
} }
} }

View file

@ -4,9 +4,9 @@ import eu.kanade.tachiyomi.source.model.Page
import rx.Observable import rx.Observable
fun HttpSource.getImageUrl(page: Page): Observable<Page> { fun HttpSource.getImageUrl(page: Page): Observable<Page> {
page.status = Page.LOAD_PAGE page.status = Page.State.LOAD_PAGE
return fetchImageUrl(page) return fetchImageUrl(page)
.doOnError { page.status = Page.ERROR } .doOnError { page.status = Page.State.ERROR }
.onErrorReturn { null } .onErrorReturn { null }
.doOnNext { page.imageUrl = it } .doOnNext { page.imageUrl = it }
.map { page } .map { page }