Browse Source

add option to skip chapters marked read (#1791)

Carlos 6 years ago
parent
commit
77296348a0

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt

@@ -107,6 +107,8 @@ object PreferenceKeys {
 
     const val defaultCategory = "default_category"
 
+    const val skipRead = "skip_read"
+
     const val downloadBadge = "display_download_badge"
 
     @Deprecated("Use the preferences of the source")

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -167,6 +167,8 @@ class PreferencesHelper(val context: Context) {
 
     fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
 
+    fun skipRead() = prefs.getBoolean(Keys.skipRead, false)
+
     fun migrateFlags() = rxPrefs.getInteger("migrate_flags", Int.MAX_VALUE)
 
     fun trustedSignatures() = rxPrefs.getStringSet("trusted_signatures", emptySet())

+ 155 - 142
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt

@@ -32,7 +32,7 @@ import timber.log.Timber
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import java.io.File
-import java.util.Date
+import java.util.*
 import java.util.concurrent.TimeUnit
 
 /**
@@ -84,12 +84,25 @@ class ReaderPresenter(
     private val chapterList by lazy {
         val manga = manga!!
         val dbChapters = db.getChapters(manga).executeAsBlocking()
+
         val selectedChapter = dbChapters.find { it.id == chapterId }
-            ?: error("Requested chapter of id $chapterId not found in chapter list")
+                ?: error("Requested chapter of id $chapterId not found in chapter list")
+
+        val chaptersForReader =
+                if (preferences.skipRead()) {
+                    var list = dbChapters.filter { it -> !it.read }.toMutableList()
+                    val find = list.find { it.id == chapterId }
+                    if (find == null) {
+                        list.add(selectedChapter)
+                    }
+                    list
+                } else {
+                    dbChapters
+                }
 
         when (manga.sorting) {
-            Manga.SORTING_SOURCE -> ChapterLoadBySource().get(dbChapters)
-            Manga.SORTING_NUMBER -> ChapterLoadByNumber().get(dbChapters, selectedChapter)
+            Manga.SORTING_SOURCE -> ChapterLoadBySource().get(chaptersForReader)
+            Manga.SORTING_NUMBER -> ChapterLoadByNumber().get(chaptersForReader, selectedChapter)
             else -> error("Unknown sorting method")
         }.map(::ReaderChapter)
     }
@@ -165,12 +178,12 @@ class ReaderPresenter(
         if (!needsInit()) return
 
         db.getManga(mangaId).asRxObservable()
-            .first()
-            .observeOn(AndroidSchedulers.mainThread())
-            .doOnNext { init(it, initialChapterId) }
-            .subscribeFirst({ _, _ ->
-                // Ignore onNext event
-            }, ReaderActivity::setInitialChapterError)
+                .first()
+                .observeOn(AndroidSchedulers.mainThread())
+                .doOnNext { init(it, initialChapterId) }
+                .subscribeFirst({ _, _ ->
+                    // Ignore onNext event
+                }, ReaderActivity::setInitialChapterError)
     }
 
     /**
@@ -193,13 +206,13 @@ class ReaderPresenter(
         // Read chapterList from an io thread because it's retrieved lazily and would block main.
         activeChapterSubscription?.unsubscribe()
         activeChapterSubscription = Observable
-            .fromCallable { chapterList.first { chapterId == it.chapter.id } }
-            .flatMap { getLoadObservable(loader!!, it) }
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .subscribeFirst({ _, _ ->
-                // Ignore onNext event
-            }, ReaderActivity::setInitialChapterError)
+                .fromCallable { chapterList.first { chapterId == it.chapter.id } }
+                .flatMap { getLoadObservable(loader!!, it) }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribeFirst({ _, _ ->
+                    // Ignore onNext event
+                }, ReaderActivity::setInitialChapterError)
     }
 
     /**
@@ -214,23 +227,23 @@ class ReaderPresenter(
             chapter: ReaderChapter
     ): Observable<ViewerChapters> {
         return loader.loadChapter(chapter)
-            .andThen(Observable.fromCallable {
-                val chapterPos = chapterList.indexOf(chapter)
-
-                ViewerChapters(chapter,
-                        chapterList.getOrNull(chapterPos - 1),
-                        chapterList.getOrNull(chapterPos + 1))
-            })
-            .observeOn(AndroidSchedulers.mainThread())
-            .doOnNext { newChapters ->
-                val oldChapters = viewerChaptersRelay.value
-
-                // Add new references first to avoid unnecessary recycling
-                newChapters.ref()
-                oldChapters?.unref()
-
-                viewerChaptersRelay.call(newChapters)
-            }
+                .andThen(Observable.fromCallable {
+                    val chapterPos = chapterList.indexOf(chapter)
+
+                    ViewerChapters(chapter,
+                            chapterList.getOrNull(chapterPos - 1),
+                            chapterList.getOrNull(chapterPos + 1))
+                })
+                .observeOn(AndroidSchedulers.mainThread())
+                .doOnNext { newChapters ->
+                    val oldChapters = viewerChaptersRelay.value
+
+                    // Add new references first to avoid unnecessary recycling
+                    newChapters.ref()
+                    oldChapters?.unref()
+
+                    viewerChaptersRelay.call(newChapters)
+                }
     }
 
     /**
@@ -244,10 +257,10 @@ class ReaderPresenter(
 
         activeChapterSubscription?.unsubscribe()
         activeChapterSubscription = getLoadObservable(loader, chapter)
-            .toCompletable()
-            .onErrorComplete()
-            .subscribe()
-            .also(::add)
+                .toCompletable()
+                .onErrorComplete()
+                .subscribe()
+                .also(::add)
     }
 
     /**
@@ -262,13 +275,13 @@ class ReaderPresenter(
 
         activeChapterSubscription?.unsubscribe()
         activeChapterSubscription = getLoadObservable(loader, chapter)
-            .doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
-            .doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
-            .subscribeFirst({ view, _ ->
-                view.moveToPageIndex(0)
-            }, { _, _ ->
-                // Ignore onError event, viewers handle that state
-            })
+                .doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
+                .doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
+                .subscribeFirst({ view, _ ->
+                    view.moveToPageIndex(0)
+                }, { _, _ ->
+                    // Ignore onError event, viewers handle that state
+                })
     }
 
     /**
@@ -285,12 +298,12 @@ class ReaderPresenter(
         val loader = loader ?: return
 
         loader.loadChapter(chapter)
-            .observeOn(AndroidSchedulers.mainThread())
-            // Update current chapters whenever a chapter is preloaded
-            .doOnCompleted { viewerChaptersRelay.value?.let(viewerChaptersRelay::call) }
-            .onErrorComplete()
-            .subscribe()
-            .also(::add)
+                .observeOn(AndroidSchedulers.mainThread())
+                // Update current chapters whenever a chapter is preloaded
+                .doOnCompleted { viewerChaptersRelay.value?.let(viewerChaptersRelay::call) }
+                .onErrorComplete()
+                .subscribe()
+                .also(::add)
     }
 
     /**
@@ -331,9 +344,9 @@ class ReaderPresenter(
      */
     private fun saveChapterProgress(chapter: ReaderChapter) {
         db.updateChapterProgress(chapter.chapter).asRxCompletable()
-            .onErrorComplete()
-            .subscribeOn(Schedulers.io())
-            .subscribe()
+                .onErrorComplete()
+                .subscribeOn(Schedulers.io())
+                .subscribe()
     }
 
     /**
@@ -342,9 +355,9 @@ class ReaderPresenter(
     private fun saveChapterHistory(chapter: ReaderChapter) {
         val history = History.create(chapter.chapter).apply { last_read = Date().time }
         db.updateHistoryLastRead(history).asRxCompletable()
-            .onErrorComplete()
-            .subscribeOn(Schedulers.io())
-            .subscribe()
+                .onErrorComplete()
+                .subscribeOn(Schedulers.io())
+                .subscribe()
     }
 
     /**
@@ -394,18 +407,18 @@ class ReaderPresenter(
         db.updateMangaViewer(manga).executeAsBlocking()
 
         Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
-            .subscribeFirst({ view, _ ->
-                val currChapters = viewerChaptersRelay.value
-                if (currChapters != null) {
-                    // Save current page
-                    val currChapter = currChapters.currChapter
-                    currChapter.requestedPage = currChapter.chapter.last_page_read
-
-                    // Emit manga and chapters to the new viewer
-                    view.setManga(manga)
-                    view.setChapters(currChapters)
-                }
-            })
+                .subscribeFirst({ view, _ ->
+                    val currChapters = viewerChaptersRelay.value
+                    if (currChapters != null) {
+                        // Save current page
+                        val currChapter = currChapters.currChapter
+                        currChapter.requestedPage = currChapter.chapter.last_page_read
+
+                        // Emit manga and chapters to the new viewer
+                        view.setManga(manga)
+                        view.setChapters(currChapters)
+                    }
+                })
     }
 
     /**
@@ -446,22 +459,22 @@ class ReaderPresenter(
 
         // Pictures directory.
         val destDir = File(Environment.getExternalStorageDirectory().absolutePath +
-                           File.separator + Environment.DIRECTORY_PICTURES +
-                           File.separator + "Tachiyomi")
+                File.separator + Environment.DIRECTORY_PICTURES +
+                File.separator + "Tachiyomi")
 
         // Copy file in background.
         Observable.fromCallable { saveImage(page, destDir, manga) }
-            .doOnNext { file ->
-                DiskUtil.scanMedia(context, file)
-                notifier.onComplete(file)
-            }
-            .doOnError { notifier.onError(it.message) }
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .subscribeFirst(
-                    { view, file -> view.onSaveImageResult(SaveImageResult.Success(file)) },
-                    { view, error -> view.onSaveImageResult(SaveImageResult.Error(error)) }
-            )
+                .doOnNext { file ->
+                    DiskUtil.scanMedia(context, file)
+                    notifier.onComplete(file)
+                }
+                .doOnError { notifier.onError(it.message) }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribeFirst(
+                        { view, file -> view.onSaveImageResult(SaveImageResult.Success(file)) },
+                        { view, error -> view.onSaveImageResult(SaveImageResult.Error(error)) }
+                )
     }
 
     /**
@@ -479,13 +492,13 @@ class ReaderPresenter(
         val destDir = File(context.cacheDir, "shared_image")
 
         Observable.fromCallable { destDir.delete() } // Keep only the last shared file
-            .map { saveImage(page, destDir, manga) }
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .subscribeFirst(
-                    { view, file -> view.onShareImageResult(file) },
-                    { view, error -> /* Empty */ }
-            )
+                .map { saveImage(page, destDir, manga) }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribeFirst(
+                        { view, file -> view.onShareImageResult(file) },
+                        { view, error -> /* Empty */ }
+                )
     }
 
     /**
@@ -497,28 +510,28 @@ class ReaderPresenter(
         val stream = page.stream ?: return
 
         Observable
-            .fromCallable {
-                if (manga.source == LocalSource.ID) {
-                    val context = Injekt.get<Application>()
-                    LocalSource.updateCover(context, manga, stream())
-                    R.string.cover_updated
-                    SetAsCoverResult.Success
-                } else {
-                    val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
-                    if (manga.favorite) {
-                        coverCache.copyToCache(thumbUrl, stream())
+                .fromCallable {
+                    if (manga.source == LocalSource.ID) {
+                        val context = Injekt.get<Application>()
+                        LocalSource.updateCover(context, manga, stream())
+                        R.string.cover_updated
                         SetAsCoverResult.Success
                     } else {
-                        SetAsCoverResult.AddToLibraryFirst
+                        val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
+                        if (manga.favorite) {
+                            coverCache.copyToCache(thumbUrl, stream())
+                            SetAsCoverResult.Success
+                        } else {
+                            SetAsCoverResult.AddToLibraryFirst
+                        }
                     }
                 }
-            }
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .subscribeFirst(
-                    { view, result -> view.onSetAsCoverResult(result) },
-                    { view, _ -> view.onSetAsCoverResult(SetAsCoverResult.Error) }
-            )
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribeFirst(
+                        { view, result -> view.onSetAsCoverResult(result) },
+                        { view, _ -> view.onSetAsCoverResult(SetAsCoverResult.Error) }
+                )
     }
 
     /**
@@ -559,26 +572,26 @@ class ReaderPresenter(
         val trackManager = Injekt.get<TrackManager>()
 
         db.getTracks(manga).asRxSingle()
-            .flatMapCompletable { trackList ->
-                Completable.concat(trackList.map { track ->
-                    val service = trackManager.getService(track.sync_id)
-                    if (service != null && service.isLogged && lastChapterRead > track.last_chapter_read) {
-                        track.last_chapter_read = lastChapterRead
-
-                        // We wan't these to execute even if the presenter is destroyed and leaks
-                        // for a while. The view can still be garbage collected.
-                        Observable.defer { service.update(track) }
-                            .map { db.insertTrack(track).executeAsBlocking() }
-                            .toCompletable()
-                            .onErrorComplete()
-                    } else {
-                        Completable.complete()
-                    }
-                })
-            }
-            .onErrorComplete()
-            .subscribeOn(Schedulers.io())
-            .subscribe()
+                .flatMapCompletable { trackList ->
+                    Completable.concat(trackList.map { track ->
+                        val service = trackManager.getService(track.sync_id)
+                        if (service != null && service.isLogged && lastChapterRead > track.last_chapter_read) {
+                            track.last_chapter_read = lastChapterRead
+
+                            // We wan't these to execute even if the presenter is destroyed and leaks
+                            // for a while. The view can still be garbage collected.
+                            Observable.defer { service.update(track) }
+                                    .map { db.insertTrack(track).executeAsBlocking() }
+                                    .toCompletable()
+                                    .onErrorComplete()
+                        } else {
+                            Completable.complete()
+                        }
+                    })
+                }
+                .onErrorComplete()
+                .subscribeOn(Schedulers.io())
+                .subscribe()
     }
 
     /**
@@ -594,19 +607,19 @@ class ReaderPresenter(
         if (removeAfterReadSlots == -1) return
 
         Completable
-            .fromCallable {
-                // Position of the read chapter
-                val position = chapterList.indexOf(chapter)
-
-                // Retrieve chapter to delete according to preference
-                val chapterToDelete = chapterList.getOrNull(position - removeAfterReadSlots)
-                if (chapterToDelete != null) {
-                    downloadManager.enqueueDeleteChapters(listOf(chapterToDelete.chapter), manga)
+                .fromCallable {
+                    // Position of the read chapter
+                    val position = chapterList.indexOf(chapter)
+
+                    // Retrieve chapter to delete according to preference
+                    val chapterToDelete = chapterList.getOrNull(position - removeAfterReadSlots)
+                    if (chapterToDelete != null) {
+                        downloadManager.enqueueDeleteChapters(listOf(chapterToDelete.chapter), manga)
+                    }
                 }
-            }
-            .onErrorComplete()
-            .subscribeOn(Schedulers.io())
-            .subscribe()
+                .onErrorComplete()
+                .subscribeOn(Schedulers.io())
+                .subscribe()
     }
 
     /**
@@ -615,9 +628,9 @@ class ReaderPresenter(
      */
     private fun deletePendingChapters() {
         Completable.fromCallable { downloadManager.deletePendingChapters() }
-            .onErrorComplete()
-            .subscribeOn(Schedulers.io())
-            .subscribe()
+                .onErrorComplete()
+                .subscribeOn(Schedulers.io())
+                .subscribe()
     }
 
 }

+ 5 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt

@@ -63,6 +63,11 @@ class SettingsReaderController : SettingsController() {
             defaultValue = "500"
             summary = "%s"
         }
+        switchPreference {
+            key = Keys.skipRead
+            titleRes = R.string.pref_skip_read_chapters
+            defaultValue = false
+        }
         switchPreference {
             key = Keys.fullscreen
             titleRes = R.string.pref_fullscreen

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -178,6 +178,7 @@
     <string name="pref_custom_brightness">Use custom brightness</string>
     <string name="pref_custom_color_filter">Use custom color filter</string>
     <string name="pref_keep_screen_on">Keep screen on</string>
+    <string name="pref_skip_read_chapters">Skip chapters marked read</string>
     <string name="pref_reader_navigation">Navigation</string>
     <string name="pref_read_with_volume_keys">Volume keys</string>
     <string name="pref_read_with_volume_keys_inverted">Invert volume keys</string>