mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	add option to skip chapters marked read (#1791)
This commit is contained in:
		| @@ -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") | ||||
|   | ||||
| @@ -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()) | ||||
|   | ||||
| @@ -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) | ||||
|                 .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 | ||||
|                     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() | ||||
|                     // Add new references first to avoid unnecessary recycling | ||||
|                     newChapters.ref() | ||||
|                     oldChapters?.unref() | ||||
|  | ||||
|                 viewerChaptersRelay.call(newChapters) | ||||
|             } | ||||
|                     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 | ||||
|                 .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) | ||||
|                 } | ||||
|             }) | ||||
|                         // 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 | ||||
|                 .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() | ||||
|                             // 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) | ||||
|                 .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) | ||||
|                     // 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() | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user