Linting fixes

This commit is contained in:
arkon
2020-04-25 14:24:45 -04:00
parent 4da760d614
commit 3f63b320c4
272 changed files with 4167 additions and 3602 deletions
@@ -26,7 +26,8 @@ class ChapterLoadByNumber {
// If there is only one chapter for this number, use it
chaptersForNumber.size == 1 -> chaptersForNumber.first()
// Prefer a chapter of the same scanlator as the selected
else -> chaptersForNumber.find { it.scanlator == selectedChapter.scanlator }
else ->
chaptersForNumber.find { it.scanlator == selectedChapter.scanlator }
?: chaptersForNumber.first()
}
chapters.add(preferredChapter)
@@ -47,8 +47,8 @@ class PageIndicatorTextView(
// A span object with text outlining properties
val spanOutline = OutlineSpan(
strokeColor = strokeColor,
strokeWidth = 4f
strokeColor = strokeColor,
strokeWidth = 4f
)
}
}
@@ -127,10 +127,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
* Called when the activity is created. Initializes the presenter and configuration.
*/
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(when (preferences.readerTheme().get()) {
0 -> R.style.Theme_Reader_Light
else -> R.style.Theme_Reader
})
setTheme(
when (preferences.readerTheme().get()) {
0 -> R.style.Theme_Reader_Light
else -> R.style.Theme_Reader
}
)
super.onCreate(savedInstanceState)
binding = ReaderActivityBinding.inflate(layoutInflater)
@@ -275,10 +277,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets ->
if (!window.isDefaultBar()) {
binding.readerMenu.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom)
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom
)
}
insets
}
@@ -293,18 +296,20 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
})
binding.leftChapter.setOnClickListener {
if (viewer != null) {
if (viewer is R2LPagerViewer)
if (viewer is R2LPagerViewer) {
loadNextChapter()
else
} else {
loadPreviousChapter()
}
}
}
binding.rightChapter.setOnClickListener {
if (viewer != null) {
if (viewer is R2LPagerViewer)
if (viewer is R2LPagerViewer) {
loadPreviousChapter()
else
} else {
loadNextChapter()
}
}
}
@@ -590,11 +595,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
* depending on the [result].
*/
fun onSetAsCoverResult(result: ReaderPresenter.SetAsCoverResult) {
toast(when (result) {
Success -> R.string.cover_updated
AddToLibraryFirst -> R.string.notification_first_add_to_library
Error -> R.string.notification_cover_update_failed
})
toast(
when (result) {
Success -> R.string.cover_updated
AddToLibraryFirst -> R.string.notification_first_add_to_library
Error -> R.string.notification_cover_update_failed
}
)
}
/**
@@ -614,10 +621,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
val sharedRotation = preferences.rotation().asObservable().share()
val initialRotation = sharedRotation.take(1)
val rotationUpdates = sharedRotation.skip(1)
.delay(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.delay(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
subscriptions += Observable.merge(initialRotation, rotationUpdates)
.subscribe { setOrientation(it) }
.subscribe { setOrientation(it) }
preferences.readerTheme().asFlow()
.drop(1) // We only care about updates
@@ -700,10 +707,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
* Sets the 32-bit color mode according to [enabled].
*/
private fun setTrueColor(enabled: Boolean) {
if (enabled)
if (enabled) {
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.ARGB_8888)
else
} else {
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.RGB_565)
}
}
@TargetApi(Build.VERSION_CODES.P)
@@ -214,8 +214,9 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet
brightness_overlay.gone()
}
if (!isDisabled)
if (!isDisabled) {
txt_brightness_seekbar_value.text = value.toString()
}
}
/**
@@ -17,14 +17,16 @@ class ReaderColorFilterView(
fun setFilterColor(color: Int, filterMode: Int) {
colorFilterPaint.color = color
colorFilterPaint.xfermode = PorterDuffXfermode(when (filterMode) {
1 -> PorterDuff.Mode.MULTIPLY
2 -> PorterDuff.Mode.SCREEN
3 -> PorterDuff.Mode.OVERLAY
4 -> PorterDuff.Mode.LIGHTEN
5 -> PorterDuff.Mode.DARKEN
else -> PorterDuff.Mode.SRC_OVER
})
colorFilterPaint.xfermode = PorterDuffXfermode(
when (filterMode) {
1 -> PorterDuff.Mode.MULTIPLY
2 -> PorterDuff.Mode.SCREEN
3 -> PorterDuff.Mode.OVERLAY
4 -> PorterDuff.Mode.LIGHTEN
5 -> PorterDuff.Mode.DARKEN
else -> PorterDuff.Mode.SRC_OVER
}
)
invalidate()
}
@@ -44,13 +44,13 @@ class ReaderPageSheet(
if (page.status != Page.READY) return
MaterialDialog(activity)
.message(R.string.confirm_set_image_as_cover)
.positiveButton(android.R.string.ok) {
activity.setAsCover(page)
dismiss()
}
.negativeButton(android.R.string.cancel)
.show()
.message(R.string.confirm_set_image_as_cover)
.positiveButton(android.R.string.ok) {
activity.setAsCover(page)
dismiss()
}
.negativeButton(android.R.string.cancel)
.show()
}
/**
@@ -88,38 +88,40 @@ class ReaderPresenter(
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() || preferences.skipFiltered()) {
val list = dbChapters
.filter {
if (preferences.skipRead() && it.read) {
if (preferences.skipRead() || preferences.skipFiltered()) {
val list = dbChapters
.filter {
if (preferences.skipRead() && it.read) {
return@filter false
} else if (preferences.skipFiltered()) {
if (
(manga.readFilter == Manga.SHOW_READ && !it.read) ||
(manga.readFilter == Manga.SHOW_UNREAD && it.read) ||
(
manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
!downloadManager.isChapterDownloaded(it, manga)
) ||
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
) {
return@filter false
} else if (preferences.skipFiltered()) {
if (
(manga.readFilter == Manga.SHOW_READ && !it.read) ||
(manga.readFilter == Manga.SHOW_UNREAD && it.read) ||
(manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
!downloadManager.isChapterDownloaded(it, manga)) ||
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
) {
return@filter false
}
}
true
}
.toMutableList()
val find = list.find { it.id == chapterId }
if (find == null) {
list.add(selectedChapter)
true
}
list
} else {
dbChapters
.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(chaptersForReader)
@@ -198,12 +200,15 @@ class ReaderPresenter(
if (!needsInit()) return
db.getManga(mangaId).asRxObservable()
.first()
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { init(it, initialChapterId) }
.subscribeFirst({ _, _ ->
.first()
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { init(it, initialChapterId) }
.subscribeFirst(
{ _, _ ->
// Ignore onNext event
}, ReaderActivity::setInitialChapterError)
},
ReaderActivity::setInitialChapterError
)
}
/**
@@ -241,13 +246,16 @@ 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({ _, _ ->
.fromCallable { chapterList.first { chapterId == it.chapter.id } }
.flatMap { getLoadObservable(loader!!, it) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeFirst(
{ _, _ ->
// Ignore onNext event
}, ReaderActivity::setInitialChapterError)
},
ReaderActivity::setInitialChapterError
)
}
/**
@@ -262,23 +270,27 @@ class ReaderPresenter(
chapter: ReaderChapter
): Observable<ViewerChapters> {
return loader.loadChapter(chapter)
.andThen(Observable.fromCallable {
.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)
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)
}
}
/**
@@ -292,10 +304,10 @@ class ReaderPresenter(
activeChapterSubscription?.unsubscribe()
activeChapterSubscription = getLoadObservable(loader, chapter)
.toCompletable()
.onErrorComplete()
.subscribe()
.also(::add)
.toCompletable()
.onErrorComplete()
.subscribe()
.also(::add)
}
/**
@@ -310,13 +322,16 @@ class ReaderPresenter(
activeChapterSubscription?.unsubscribe()
activeChapterSubscription = getLoadObservable(loader, chapter)
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
.subscribeFirst({ view, _ ->
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
.subscribeFirst(
{ view, _ ->
view.moveToPageIndex(0)
}, { _, _ ->
},
{ _, _ ->
// Ignore onError event, viewers handle that state
})
}
)
}
/**
@@ -333,12 +348,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)
}
/**
@@ -380,9 +395,9 @@ class ReaderPresenter(
*/
private fun saveChapterProgress(chapter: ReaderChapter) {
db.updateChapterProgress(chapter.chapter).asRxCompletable()
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
}
/**
@@ -391,9 +406,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()
}
/**
@@ -456,18 +471,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)
}
})
}
/**
@@ -484,7 +499,7 @@ class ReaderPresenter(
// Build destination file.
val filenameSuffix = " - ${page.number}.${type.extension}"
val filename = DiskUtil.buildValidFilename(
"${manga.title} - ${chapter.name}".takeBytes(MAX_FILE_NAME_BYTES - filenameSuffix.byteSize())
"${manga.title} - ${chapter.name}".takeBytes(MAX_FILE_NAME_BYTES - filenameSuffix.byteSize())
) + filenameSuffix
val destFile = File(directory, filename)
@@ -509,23 +524,25 @@ class ReaderPresenter(
notifier.onClear()
// Pictures directory.
val destDir = File(Environment.getExternalStorageDirectory().absolutePath +
val destDir = File(
Environment.getExternalStorageDirectory().absolutePath +
File.separator + Environment.DIRECTORY_PICTURES +
File.separator + "Tachiyomi")
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)) }
)
}
/**
@@ -543,13 +560,13 @@ class ReaderPresenter(
val destDir = File(context.cacheDir, "shared_image")
Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file
.map { saveImage(page, destDir, manga) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeFirst(
{ view, file -> view.onShareImageResult(file) },
{ _, _ -> /* Empty */ }
)
.map { saveImage(page, destDir, manga) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeFirst(
{ view, file -> view.onShareImageResult(file) },
{ _, _ -> /* Empty */ }
)
}
/**
@@ -561,28 +578,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
.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())
SetAsCoverResult.Success
} else {
val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
if (manga.favorite) {
coverCache.copyToCache(thumbUrl, stream())
SetAsCoverResult.Success
} else {
SetAsCoverResult.AddToLibraryFirst
}
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) }
)
}
/**
@@ -613,8 +630,9 @@ class ReaderPresenter(
val trackManager = Injekt.get<TrackManager>()
db.getTracks(manga).asRxSingle()
.flatMapCompletable { trackList ->
Completable.concat(trackList.map { track ->
.flatMapCompletable { trackList ->
Completable.concat(
trackList.map { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged && chapterRead > track.last_chapter_read) {
track.last_chapter_read = chapterRead
@@ -622,17 +640,18 @@ class ReaderPresenter(
// 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()
.map { db.insertTrack(track).executeAsBlocking() }
.toCompletable()
.onErrorComplete()
} else {
Completable.complete()
}
})
}
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
}
)
}
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
}
/**
@@ -648,19 +667,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()
}
/**
@@ -669,9 +688,9 @@ class ReaderPresenter(
*/
private fun deletePendingChapters() {
Completable.fromCallable { downloadManager.deletePendingChapters() }
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
}
companion object {
@@ -37,12 +37,12 @@ class SaveImageNotifier(private val context: Context) {
*/
fun onComplete(file: File) {
val bitmap = GlideApp.with(context)
.asBitmap()
.load(file)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.submit(720, 1280)
.get()
.asBitmap()
.load(file)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.submit(720, 1280)
.get()
if (bitmap != null) {
showCompleteNotification(file, bitmap)
@@ -66,13 +66,17 @@ class SaveImageNotifier(private val context: Context) {
setContentIntent(NotificationHandler.openImagePendingActivity(context, file))
// Share action
addAction(R.drawable.ic_share_24dp,
context.getString(R.string.action_share),
NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId))
addAction(
R.drawable.ic_share_24dp,
context.getString(R.string.action_share),
NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId)
)
// Delete action
addAction(R.drawable.ic_delete_24dp,
context.getString(R.string.action_delete),
NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId))
addAction(
R.drawable.ic_delete_24dp,
context.getString(R.string.action_delete),
NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId)
)
updateNotification()
}
@@ -31,34 +31,34 @@ class ChapterLoader(
}
return Observable.just(chapter)
.doOnNext { chapter.state = ReaderChapter.State.Loading }
.observeOn(Schedulers.io())
.flatMap { readerChapter ->
Timber.d("Loading pages for ${chapter.chapter.name}")
.doOnNext { chapter.state = ReaderChapter.State.Loading }
.observeOn(Schedulers.io())
.flatMap { readerChapter ->
Timber.d("Loading pages for ${chapter.chapter.name}")
val loader = getPageLoader(readerChapter)
chapter.pageLoader = loader
val loader = getPageLoader(readerChapter)
chapter.pageLoader = loader
loader.getPages().take(1).doOnNext { pages ->
pages.forEach { it.chapter = chapter }
}
loader.getPages().take(1).doOnNext { pages ->
pages.forEach { it.chapter = chapter }
}
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { pages ->
if (pages.isEmpty()) {
throw Exception("Page list is empty")
}
chapter.state = ReaderChapter.State.Loaded(pages)
// If the chapter is partially read, set the starting page to the last the user read
// otherwise use the requested page.
if (!chapter.chapter.read) {
chapter.requestedPage = chapter.chapter.last_page_read
}
}
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { pages ->
if (pages.isEmpty()) {
throw Exception("Page list is empty")
}
.toCompletable()
.doOnError { chapter.state = ReaderChapter.State.Error(it) }
chapter.state = ReaderChapter.State.Loaded(pages)
// If the chapter is partially read, set the starting page to the last the user read
// otherwise use the requested page.
if (!chapter.chapter.read) {
chapter.requestedPage = chapter.chapter.last_page_read
}
}
.toCompletable()
.doOnError { chapter.state = ReaderChapter.State.Error(it) }
}
/**
@@ -19,16 +19,16 @@ class DirectoryPageLoader(val file: File) : PageLoader() {
*/
override fun getPages(): Observable<List<ReaderPage>> {
return file.listFiles()
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
.sortedWith(Comparator<File> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
.mapIndexed { i, file ->
val streamFn = { FileInputStream(file) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
.sortedWith(Comparator<File> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
.mapIndexed { i, file ->
val streamFn = { FileInputStream(file) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.let { Observable.just(it) }
}
.let { Observable.just(it) }
}
/**
@@ -31,15 +31,15 @@ class DownloadPageLoader(
*/
override fun getPages(): Observable<List<ReaderPage>> {
return downloadManager.buildPageList(source, manga, chapter.chapter)
.map { pages ->
pages.map { page ->
ReaderPage(page.index, page.url, page.imageUrl) {
context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!!
}.apply {
status = Page.READY
}
.map { pages ->
pages.map { page ->
ReaderPage(page.index, page.url, page.imageUrl) {
context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!!
}.apply {
status = Page.READY
}
}
}
}
override fun getPage(page: ReaderPage): Observable<Int> {
@@ -30,24 +30,26 @@ class EpubPageLoader(file: File) : PageLoader() {
*/
override fun getPages(): Observable<List<ReaderPage>> {
return epub.getImagesFromPages()
.mapIndexed { i, path ->
val streamFn = { epub.getInputStream(epub.getEntry(path)!!) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.mapIndexed { i, path ->
val streamFn = { epub.getInputStream(epub.getEntry(path)!!) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.let { Observable.just(it) }
}
.let { Observable.just(it) }
}
/**
* Returns an observable that emits a ready state unless the loader was recycled.
*/
override fun getPage(page: ReaderPage): Observable<Int> {
return Observable.just(if (isRecycled) {
Page.ERROR
} else {
Page.READY
})
return Observable.just(
if (isRecycled) {
Page.ERROR
} else {
Page.READY
}
)
}
}
@@ -42,16 +42,19 @@ class HttpPageLoader(
init {
subscriptions += Observable.defer { Observable.just(queue.take().page) }
.filter { it.status == Page.QUEUE }
.concatMap { source.fetchImageFromCacheThenNet(it) }
.repeat()
.subscribeOn(Schedulers.io())
.subscribe({
}, { error ->
.filter { it.status == Page.QUEUE }
.concatMap { source.fetchImageFromCacheThenNet(it) }
.repeat()
.subscribeOn(Schedulers.io())
.subscribe(
{
},
{ error ->
if (error !is InterruptedException) {
Timber.e(error)
}
})
}
)
}
/**
@@ -66,14 +69,14 @@ class HttpPageLoader(
val pages = chapter.pages
if (pages != null) {
Completable
.fromAction {
// Convert to pages without reader information
val pagesToSave = pages.map { Page(it.index, it.url, it.imageUrl) }
chapterCache.putPageListToCache(chapter.chapter, pagesToSave)
}
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
.fromAction {
// Convert to pages without reader information
val pagesToSave = pages.map { Page(it.index, it.url, it.imageUrl) }
chapterCache.putPageListToCache(chapter.chapter, pagesToSave)
}
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
}
}
@@ -83,14 +86,14 @@ class HttpPageLoader(
*/
override fun getPages(): Observable<List<ReaderPage>> {
return chapterCache
.getPageListFromCache(chapter.chapter)
.onErrorResumeNext { source.fetchPageList(chapter.chapter) }
.map { pages ->
pages.mapIndexed { index, page ->
// Don't trust sources and use our own indexing
ReaderPage(index, page.url, page.imageUrl)
}
.getPageListFromCache(chapter.chapter)
.onErrorResumeNext { source.fetchPageList(chapter.chapter) }
.map { pages ->
pages.mapIndexed { index, page ->
// Don't trust sources and use our own indexing
ReaderPage(index, page.url, page.imageUrl)
}
}
}
/**
@@ -121,16 +124,16 @@ class HttpPageLoader(
queuedPages += preloadNextPages(page, preloadSize)
statusSubject.startWith(page.status)
.doOnUnsubscribe {
queuedPages.forEach {
if (it.page.status == Page.QUEUE) {
queue.remove(it)
}
.doOnUnsubscribe {
queuedPages.forEach {
if (it.page.status == Page.QUEUE) {
queue.remove(it)
}
}
}
}
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
}
/**
@@ -143,12 +146,12 @@ class HttpPageLoader(
if (pageIndex == pages.lastIndex) return emptyList()
return pages
.subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size))
.mapNotNull {
if (it.status == Page.QUEUE) {
PriorityPage(it, 0).apply { queue.offer(this) }
} else null
}
.subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size))
.mapNotNull {
if (it.status == Page.QUEUE) {
PriorityPage(it, 0).apply { queue.offer(this) }
} else null
}
}
/**
@@ -186,19 +189,20 @@ class HttpPageLoader(
* @param page the page whose source image has to be downloaded.
*/
private fun HttpSource.fetchImageFromCacheThenNet(page: ReaderPage): Observable<ReaderPage> {
return if (page.imageUrl.isNullOrEmpty())
return if (page.imageUrl.isNullOrEmpty()) {
getImageUrl(page).flatMap { getCachedImage(it) }
else
} else {
getCachedImage(page)
}
}
private fun HttpSource.getImageUrl(page: ReaderPage): Observable<ReaderPage> {
page.status = Page.LOAD_PAGE
return fetchImageUrl(page)
.doOnError { page.status = Page.ERROR }
.onErrorReturn { null }
.doOnNext { page.imageUrl = it }
.map { page }
.doOnError { page.status = Page.ERROR }
.onErrorReturn { null }
.doOnNext { page.imageUrl = it }
.map { page }
}
/**
@@ -211,19 +215,19 @@ class HttpPageLoader(
val imageUrl = page.imageUrl ?: return Observable.just(page)
return Observable.just(page)
.flatMap {
if (!chapterCache.isImageInCache(imageUrl)) {
cacheImage(page)
} else {
Observable.just(page)
}
.flatMap {
if (!chapterCache.isImageInCache(imageUrl)) {
cacheImage(page)
} else {
Observable.just(page)
}
.doOnNext {
page.stream = { chapterCache.getImageFile(imageUrl).inputStream() }
page.status = Page.READY
}
.doOnError { page.status = Page.ERROR }
.onErrorReturn { page }
}
.doOnNext {
page.stream = { chapterCache.getImageFile(imageUrl).inputStream() }
page.status = Page.READY
}
.doOnError { page.status = Page.ERROR }
.onErrorReturn { page }
}
/**
@@ -234,7 +238,7 @@ class HttpPageLoader(
private fun HttpSource.cacheImage(page: ReaderPage): Observable<ReaderPage> {
page.status = Page.DOWNLOAD_IMAGE
return fetchImage(page)
.doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) }
.map { page }
.doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) }
.map { page }
}
}
@@ -43,28 +43,30 @@ class RarPageLoader(file: File) : PageLoader() {
*/
override fun getPages(): Observable<List<ReaderPage>> {
return archive.fileHeaders
.filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } }
.sortedWith(Comparator<FileHeader> { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) })
.mapIndexed { i, header ->
val streamFn = { getStream(header) }
.filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } }
.sortedWith(Comparator<FileHeader> { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) })
.mapIndexed { i, header ->
val streamFn = { getStream(header) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.let { Observable.just(it) }
}
.let { Observable.just(it) }
}
/**
* Returns an observable that emits a ready state unless the loader was recycled.
*/
override fun getPage(page: ReaderPage): Observable<Int> {
return Observable.just(if (isRecycled) {
Page.ERROR
} else {
Page.READY
})
return Observable.just(
if (isRecycled) {
Page.ERROR
} else {
Page.READY
}
)
}
/**
@@ -33,26 +33,28 @@ class ZipPageLoader(file: File) : PageLoader() {
*/
override fun getPages(): Observable<List<ReaderPage>> {
return zip.entries().toList()
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
.sortedWith(Comparator<ZipEntry> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
.mapIndexed { i, entry ->
val streamFn = { zip.getInputStream(entry) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
.sortedWith(Comparator<ZipEntry> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
.mapIndexed { i, entry ->
val streamFn = { zip.getInputStream(entry) }
ReaderPage(i).apply {
stream = streamFn
status = Page.READY
}
.let { Observable.just(it) }
}
.let { Observable.just(it) }
}
/**
* Returns an observable that emits a ready state unless the loader was recycled.
*/
override fun getPage(page: ReaderPage): Observable<Int> {
return Observable.just(if (isRecycled) {
Page.ERROR
} else {
Page.READY
})
return Observable.just(
if (isRecycled) {
Page.ERROR
} else {
Page.READY
}
)
}
}
@@ -8,11 +8,11 @@ import timber.log.Timber
data class ReaderChapter(val chapter: Chapter) {
var state: State =
State.Wait
State.Wait
set(value) {
field = value
stateRelay.call(value)
}
field = value
stateRelay.call(value)
}
private val stateRelay by lazy { BehaviorRelay.create(state) }
@@ -61,9 +61,10 @@ class ReaderProgressBar @JvmOverloads constructor(
* The rotation animation to use while the progress bar is visible.
*/
private val rotationAnimation by lazy {
RotateAnimation(0f, 360f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
RotateAnimation(
0f, 360f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
).apply {
interpolator = LinearInterpolator()
repeatCount = Animation.INFINITE
@@ -126,8 +126,8 @@ class PagerPageHolder(
val loader = page.chapter.pageLoader ?: return
statusSubscription = loader.getPage(page)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { processStatus(it) }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { processStatus(it) }
}
/**
@@ -137,11 +137,11 @@ class PagerPageHolder(
progressSubscription?.unsubscribe()
progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS)
.map { page.progress }
.distinctUntilChanged()
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value -> progressBar.setProgress(value) }
.map { page.progress }
.distinctUntilChanged()
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value -> progressBar.setProgress(value) }
}
/**
@@ -233,25 +233,25 @@ class PagerPageHolder(
var openStream: InputStream? = null
readImageHeaderSubscription = Observable
.fromCallable {
val stream = streamFn().buffered(16)
openStream = stream
.fromCallable {
val stream = streamFn().buffered(16)
openStream = stream
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated ->
if (!isAnimated) {
initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!))
} else {
initImageView().setImage(openStream!!)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated ->
if (!isAnimated) {
initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!))
} else {
initImageView().setImage(openStream!!)
}
}
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {})
}
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {})
}
/**
@@ -283,7 +283,6 @@ class PagerPageHolder(
@SuppressLint("PrivateResource")
private fun createProgressBar(): ReaderProgressBar {
return ReaderProgressBar(context, null).apply {
val size = 48.dpToPx
layoutParams = LayoutParams(size, size).apply {
gravity = Gravity.CENTER
@@ -435,35 +434,35 @@ class PagerPageHolder(
*/
private fun ImageView.setImage(stream: InputStream) {
GlideApp.with(this)
.load(stream)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
onImageDecodeError()
return false
}
.load(stream)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
onImageDecodeError()
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
if (resource is GifDrawable) {
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
}
onImageDecoded()
return false
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
if (resource is GifDrawable) {
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
}
})
.into(this)
onImageDecoded()
return false
}
})
.into(this)
}
}
@@ -140,17 +140,17 @@ class PagerTransitionHolder(
private fun observeStatus(chapter: ReaderChapter) {
statusSubscription?.unsubscribe()
statusSubscription = chapter.stateObserver
.observeOn(AndroidSchedulers.mainThread())
.subscribe { state ->
pagesContainer.removeAllViews()
when (state) {
is ReaderChapter.State.Wait -> {
}
is ReaderChapter.State.Loading -> setLoading()
is ReaderChapter.State.Error -> setError(state.error)
is ReaderChapter.State.Loaded -> setLoaded()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { state ->
pagesContainer.removeAllViews()
when (state) {
is ReaderChapter.State.Wait -> {
}
is ReaderChapter.State.Loading -> setLoading()
is ReaderChapter.State.Error -> setError(state.error)
is ReaderChapter.State.Loaded -> setLoaded()
}
}
}
/**
@@ -57,12 +57,13 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
// Add next chapter transition and pages.
nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter)
.also {
if (forceTransition ||
chapters.nextChapter?.state !is ReaderChapter.State.Loaded) {
newItems.add(it)
}
.also {
if (forceTransition ||
chapters.nextChapter?.state !is ReaderChapter.State.Loaded
) {
newItems.add(it)
}
}
if (chapters.nextChapter != null) {
// Add at most two pages, because this chapter will be selected before the user can
@@ -37,17 +37,18 @@ class WebtoonLayoutManager(activity: ReaderActivity) : LinearLayoutManager(activ
fun findLastEndVisibleItemPosition(): Int {
ensureLayoutState()
@ViewBoundsCheck.ViewBounds val preferredBoundsFlag =
(ViewBoundsCheck.FLAG_CVE_LT_PVE or ViewBoundsCheck.FLAG_CVE_EQ_PVE)
(ViewBoundsCheck.FLAG_CVE_LT_PVE or ViewBoundsCheck.FLAG_CVE_EQ_PVE)
val fromIndex = childCount - 1
val toIndex = -1
val child = if (mOrientation == HORIZONTAL)
val child = if (mOrientation == HORIZONTAL) {
mHorizontalBoundCheck
.findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0)
else
.findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0)
} else {
mVerticalBoundCheck
.findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0)
.findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0)
}
return if (child == null) NO_POSITION else getPosition(child)
}
@@ -162,8 +162,8 @@ class WebtoonPageHolder(
val page = page ?: return
val loader = page.chapter.pageLoader ?: return
statusSubscription = loader.getPage(page)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { processStatus(it) }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { processStatus(it) }
addSubscription(statusSubscription)
}
@@ -177,11 +177,11 @@ class WebtoonPageHolder(
val page = page ?: return
progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS)
.map { page.progress }
.distinctUntilChanged()
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value -> progressBar.setProgress(value) }
.map { page.progress }
.distinctUntilChanged()
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value -> progressBar.setProgress(value) }
addSubscription(progressSubscription)
}
@@ -279,29 +279,29 @@ class WebtoonPageHolder(
var openStream: InputStream? = null
readImageHeaderSubscription = Observable
.fromCallable {
val stream = streamFn().buffered(16)
openStream = stream
.fromCallable {
val stream = streamFn().buffered(16)
openStream = stream
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated ->
if (!isAnimated) {
val subsamplingView = initSubsamplingImageView()
subsamplingView.visible()
subsamplingView.setImage(ImageSource.inputStream(openStream!!))
} else {
val imageView = initImageView()
imageView.visible()
imageView.setImage(openStream!!)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated ->
if (!isAnimated) {
val subsamplingView = initSubsamplingImageView()
subsamplingView.visible()
subsamplingView.setImage(ImageSource.inputStream(openStream!!))
} else {
val imageView = initImageView()
imageView.visible()
imageView.setImage(openStream!!)
}
}
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {})
}
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {})
addSubscription(readImageHeaderSubscription)
}
@@ -489,35 +489,35 @@ class WebtoonPageHolder(
*/
private fun ImageView.setImage(stream: InputStream) {
GlideApp.with(this)
.load(stream)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
onImageDecodeError()
return false
}
.load(stream)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
onImageDecodeError()
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
if (resource is GifDrawable) {
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
}
onImageDecoded()
return false
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
if (resource is GifDrawable) {
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
}
})
.into(this)
onImageDecoded()
return false
}
})
.into(this)
}
}
@@ -59,7 +59,7 @@ open class WebtoonRecyclerView @JvmOverloads constructor(
super.onScrolled(dx, dy)
val layoutManager = layoutManager
lastVisibleItemPosition =
(layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
(layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
}
@@ -146,13 +146,13 @@ open class WebtoonRecyclerView @JvmOverloads constructor(
}
animate()
.apply {
newX?.let { x(it) }
newY?.let { y(it) }
}
.setInterpolator(DecelerateInterpolator())
.setDuration(400)
.start()
.apply {
newX?.let { x(it) }
newY?.let { y(it) }
}
.setInterpolator(DecelerateInterpolator())
.setDuration(400)
.start()
return true
}
@@ -174,8 +174,9 @@ open class WebtoonRecyclerView @JvmOverloads constructor(
fun onScale(scaleFactor: Float) {
currentScale *= scaleFactor
currentScale = currentScale.coerceIn(
MIN_RATE,
MAX_SCALE_RATE)
MIN_RATE,
MAX_SCALE_RATE
)
setScaleRate(currentScale)
@@ -143,18 +143,18 @@ class WebtoonTransitionHolder(
unsubscribeStatus()
statusSubscription = chapter.stateObserver
.observeOn(AndroidSchedulers.mainThread())
.subscribe { state ->
pagesContainer.removeAllViews()
when (state) {
is ReaderChapter.State.Wait -> {
}
is ReaderChapter.State.Loading -> setLoading()
is ReaderChapter.State.Error -> setError(state.error, transition)
is ReaderChapter.State.Loaded -> setLoaded()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { state ->
pagesContainer.removeAllViews()
when (state) {
is ReaderChapter.State.Wait -> {
}
pagesContainer.visibleIf { pagesContainer.childCount > 0 }
is ReaderChapter.State.Loading -> setLoading()
is ReaderChapter.State.Error -> setError(state.error, transition)
is ReaderChapter.State.Loaded -> setLoaded()
}
pagesContainer.visibleIf { pagesContainer.childCount > 0 }
}
addSubscription(statusSubscription)
}
@@ -291,6 +291,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
val position = layoutManager.findLastEndVisibleItemPosition()
adapter.notifyItemRangeChanged(
max(0, position - 2),
min(position + 2, adapter.itemCount - 1))
min(position + 2, adapter.itemCount - 1)
)
}
}