From 2566862e0fa24fe1ce3573169586208ec32aa0a5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 3 Feb 2016 22:55:56 +0100 Subject: [PATCH] seamless chapter transitions --- .../data/database/models/Chapter.java | 16 ++ .../data/preference/PreferencesHelper.java | 4 + .../tachiyomi/data/source/model/Page.java | 17 ++ .../tachiyomi/ui/reader/ReaderActivity.java | 37 ++- .../tachiyomi/ui/reader/ReaderMenu.java | 9 +- .../tachiyomi/ui/reader/ReaderPresenter.java | 251 +++++++++++------- .../ui/reader/viewer/base/BaseReader.java | 77 ++++-- .../base/OnChapterSingleTapListener.java | 7 - .../OnChapterBoundariesOutListener.java | 2 +- .../ui/reader/viewer/pager/Pager.java | 9 - .../viewer/pager/PagerGestureListener.java | 71 ----- .../ui/reader/viewer/pager/PagerReader.java | 102 ++++--- .../viewer/pager/PagerReaderAdapter.java | 19 +- .../viewer/pager/PagerReaderFragment.java | 38 ++- .../pager/horizontal/HorizontalPager.java | 39 +-- .../pager/horizontal/HorizontalReader.java | 19 -- .../pager/horizontal/LeftToRightReader.java | 20 +- .../pager/horizontal/RightToLeftReader.java | 38 ++- .../viewer/pager/vertical/VerticalPager.java | 39 +-- .../viewer/pager/vertical/VerticalReader.java | 10 - .../reader/viewer/webtoon/WebtoonAdapter.java | 2 +- .../reader/viewer/webtoon/WebtoonReader.java | 59 ++-- app/src/main/res/values/keys.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_reader.xml | 4 + 25 files changed, 463 insertions(+), 428 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterSingleTapListener.java rename app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/{base => pager}/OnChapterBoundariesOutListener.java (68%) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerGestureListener.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalReader.java diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.java index 86657e2ec..fc37422a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.java @@ -4,8 +4,11 @@ import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn; import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType; import java.io.Serializable; +import java.util.List; import eu.kanade.tachiyomi.data.database.tables.ChapterTable; +import eu.kanade.tachiyomi.data.download.model.Download; +import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.util.UrlUtil; @StorIOSQLiteType(table = ChapterTable.TABLE) @@ -40,6 +43,8 @@ public class Chapter implements Serializable { public int status; + private transient List pages; + public Chapter() {} public void setUrl(String url) { @@ -68,4 +73,15 @@ public class Chapter implements Serializable { return chapter; } + public List getPages() { + return pages; + } + + public void setPages(List pages) { + this.pages = pages; + } + + public boolean isDownloaded() { + return status == Download.DOWNLOADED; + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java index c945ef0d3..b3c6132fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.java @@ -128,6 +128,10 @@ public class PreferencesHelper { return rxPrefs.getInteger(getKey(R.string.pref_last_catalogue_source_key), -1); } + public boolean seamlessMode() { + return prefs.getBoolean(getKey(R.string.pref_seamless_mode_key), true); + } + public Preference catalogueAsList() { return rxPrefs.getBoolean(getKey(R.string.pref_display_catalogue_as_list), false); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java index 9763881a6..c3ec18d70 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java @@ -1,5 +1,9 @@ package eu.kanade.tachiyomi.data.source.model; +import java.io.Serializable; +import java.util.List; + +import eu.kanade.tachiyomi.data.database.models.Chapter; import eu.kanade.tachiyomi.data.network.ProgressListener; import rx.subjects.PublishSubject; @@ -8,6 +12,7 @@ public class Page implements ProgressListener { private int pageNumber; private String url; private String imageUrl; + private transient Chapter chapter; private transient String imagePath; private transient volatile int status; private transient volatile int progress; @@ -82,4 +87,16 @@ public class Page implements ProgressListener { this.statusSubject = subject; } + public Chapter getChapter() { + return chapter; + } + + public void setChapter(Chapter chapter) { + this.chapter = chapter; + } + + public boolean isLastPage() { + List chapterPages = chapter.getPages(); + return chapterPages.size() -1 == pageNumber; + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java index 27d1151a7..baffb9397 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java @@ -158,16 +158,34 @@ public class ReaderActivity extends BaseRxActivity { ToastUtil.showShort(this, R.string.page_list_error); } - public void onChapterReady(List pages, Manga manga, Chapter chapter, int currentPage) { - if (currentPage == -1) { - currentPage = pages.size() - 1; + public void onChapterAppendError() { + // Ignore + } + + public void onChapterReady(Manga manga, Chapter chapter, Page currentPage) { + List pages = chapter.getPages(); + if (currentPage == null) { + currentPage = pages.get(pages.size() - 1); } if (viewer == null) { viewer = getOrCreateViewer(manga); } - viewer.onPageListReady(pages, currentPage); - readerMenu.onChapterReady(pages.size(), manga, chapter, currentPage); + viewer.onPageListReady(chapter, currentPage); + readerMenu.setActiveManga(manga); + readerMenu.setActiveChapter(chapter, currentPage.getPageNumber()); + } + + public void onEnterChapter(Chapter chapter, int currentPage) { + if (currentPage == -1) { + currentPage = chapter.getPages().size() - 1; + } + getPresenter().setActiveChapter(chapter); + readerMenu.setActiveChapter(chapter, currentPage); + } + + public void onAppendChapter(Chapter chapter) { + viewer.onPageListAppendReady(chapter); } public void onAdjacentChapters(Chapter previous, Chapter next) { @@ -209,8 +227,9 @@ public class ReaderActivity extends BaseRxActivity { readerMenu.onPageChanged(currentPageIndex); } - public void setSelectedPage(int pageIndex) { - viewer.setSelectedPage(pageIndex); + public void gotoPageInCurrentChapter(int pageIndex) { + Page requestedPage = viewer.getCurrentPage().getChapter().getPages().get(pageIndex); + viewer.setSelectedPage(requestedPage); } public void onCenterSingleTap() { @@ -218,7 +237,7 @@ public class ReaderActivity extends BaseRxActivity { } public void requestNextChapter() { - getPresenter().setCurrentPage(viewer != null ? viewer.getCurrentPage() : 0); + getPresenter().setCurrentPage(viewer.getCurrentPage()); if (!getPresenter().loadNextChapter()) { ToastUtil.showShort(this, R.string.no_next_chapter); } @@ -226,7 +245,7 @@ public class ReaderActivity extends BaseRxActivity { } public void requestPreviousChapter() { - getPresenter().setCurrentPage(viewer != null ? viewer.getCurrentPage() : 0); + getPresenter().setCurrentPage(viewer.getCurrentPage()); if (!getPresenter().loadPreviousChapter()) { ToastUtil.showShort(this, R.string.no_previous_chapter); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java index 2645405ac..386a324a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java @@ -134,7 +134,7 @@ public class ReaderMenu { return true; } - public void onChapterReady(int numPages, Manga manga, Chapter chapter, int currentPageIndex) { + public void setActiveManga(Manga manga) { if (manga.viewer == ReaderActivity.RIGHT_TO_LEFT && !inverted) { // Invert the seekbar and textview fields for the right to left reader seekBar.setRotation(180); @@ -144,14 +144,17 @@ public class ReaderMenu { // Don't invert again on chapter change inverted = true; } + activity.setToolbarTitle(manga.title); + } + public void setActiveChapter(Chapter chapter, int currentPageIndex) { // Set initial values + int numPages = chapter.getPages().size(); totalPages.setText("" + numPages); currentPage.setText("" + (currentPageIndex + 1)); seekBar.setMax(numPages - 1); seekBar.setProgress(currentPageIndex); - activity.setToolbarTitle(manga.title); activity.setToolbarSubtitle(chapter.chapter_number != -1 ? activity.getString(R.string.chapter_subtitle, decimalFormat.format(chapter.chapter_number)) : @@ -353,7 +356,7 @@ public class ReaderMenu { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { - activity.setSelectedPage(progress); + activity.gotoPageInCurrentChapter(progress); } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.java index 561b75c0d..14ab9bc2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.java @@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter; import eu.kanade.tachiyomi.data.database.models.Manga; import eu.kanade.tachiyomi.data.database.models.MangaSync; import eu.kanade.tachiyomi.data.download.DownloadManager; +import eu.kanade.tachiyomi.data.download.model.Download; import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager; import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService; import eu.kanade.tachiyomi.data.preference.PreferencesHelper; @@ -27,6 +28,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter; import eu.kanade.tachiyomi.util.EventBusHook; import icepick.State; import rx.Observable; +import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import rx.subjects.PublishSubject; @@ -41,25 +43,25 @@ public class ReaderPresenter extends BasePresenter { @Inject SourceManager sourceManager; @State Manga manga; - @State Chapter chapter; + @State Chapter activeChapter; @State int sourceId; - @State boolean isDownloaded; - @State int currentPage; + @State int requestedPage; + private Page currentPage; private Source source; private Chapter nextChapter; private Chapter previousChapter; - private List pageList; - private List nextChapterPageList; private List mangaSyncList; private PublishSubject retryPageSubject; + private PublishSubject pageInitializerSubject; + + private boolean seamlessMode; + private Subscription appenderSubscription; private static final int GET_PAGE_LIST = 1; - private static final int GET_PAGE_IMAGES = 2; - private static final int GET_ADJACENT_CHAPTERS = 3; - private static final int RETRY_IMAGES = 4; - private static final int PRELOAD_NEXT_CHAPTER = 5; - private static final int GET_MANGA_SYNC = 6; + private static final int GET_ADJACENT_CHAPTERS = 2; + private static final int GET_MANGA_SYNC = 3; + private static final int PRELOAD_NEXT_CHAPTER = 4; @Override protected void onCreate(Bundle savedState) { @@ -67,38 +69,29 @@ public class ReaderPresenter extends BasePresenter { if (savedState != null) { source = sourceManager.get(sourceId); + initializeSubjects(); } - retryPageSubject = PublishSubject.create(); - - startable(PRELOAD_NEXT_CHAPTER, this::getPreloadNextChapterObservable, - next -> {}, - error -> Timber.e("Error preloading chapter")); - - startable(GET_PAGE_IMAGES, this::getPageImagesObservable, - next -> {}, - error -> Timber.e("Error fetching images")); + seamlessMode = prefs.seamlessMode(); startableLatestCache(GET_ADJACENT_CHAPTERS, this::getAdjacentChaptersObservable, (view, pair) -> view.onAdjacentChapters(pair.first, pair.second)); - startable(RETRY_IMAGES, this::getRetryPageObservable); + startable(PRELOAD_NEXT_CHAPTER, this::getPreloadNextChapterObservable, + next -> {}, + error -> Timber.e("Error preloading chapter")); + restartable(GET_MANGA_SYNC, () -> getMangaSyncObservable().subscribe()); restartableLatestCache(GET_PAGE_LIST, - () -> getPageListObservable() - .doOnNext(pages -> pageList = pages) - .doOnCompleted(() -> { - start(GET_ADJACENT_CHAPTERS); - start(GET_PAGE_IMAGES); - start(RETRY_IMAGES); - }), - (view, pages) -> view.onChapterReady(pages, manga, chapter, currentPage), + () -> getPageListObservable(activeChapter), + (view, chapter) -> view.onChapterReady(manga, activeChapter, currentPage), (view, error) -> view.onChapterError()); - - registerForStickyEvents(); + if (savedState == null) { + registerForStickyEvents(); + } } @Override @@ -119,43 +112,79 @@ public class ReaderPresenter extends BasePresenter { manga = event.getManga(); source = event.getSource(); sourceId = source.getId(); + initializeSubjects(); loadChapter(event.getChapter()); if (prefs.autoUpdateMangaSync()) { start(GET_MANGA_SYNC); } } + private void initializeSubjects() { + // Listen for pages initialization events + pageInitializerSubject = PublishSubject.create(); + add(pageInitializerSubject + .observeOn(Schedulers.io()) + .concatMap(chapter -> { + Observable observable; + if (chapter.isDownloaded()) { + File chapterDir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter); + observable = Observable.from(chapter.getPages()) + .flatMap(page -> downloadManager.getDownloadedImage(page, chapterDir)); + } else { + observable = source.getAllImageUrlsFromPageList(chapter.getPages()) + .flatMap(source::getCachedImage, 2) + .doOnCompleted(() -> source.savePageList(chapter.url, chapter.getPages())); + } + return observable.doOnCompleted(() -> { + if (!seamlessMode && activeChapter == chapter) { + preloadNextChapter(); + } + }); + }) + .subscribe()); + + // Listen por retry events + retryPageSubject = PublishSubject.create(); + add(retryPageSubject + .observeOn(Schedulers.io()) + .flatMap(page -> page.getImageUrl() == null ? + source.getImageUrlFromPage(page) : + Observable.just(page)) + .flatMap(source::getCachedImage) + .subscribe()); + } + // Returns the page list of a chapter - private Observable> getPageListObservable() { - return isDownloaded ? + private Observable getPageListObservable(Chapter chapter) { + return (chapter.isDownloaded() ? // Fetch the page list from disk Observable.just(downloadManager.getSavedPageList(source, manga, chapter)) : // Fetch the page list from cache or fallback to network source.getCachedPageListOrPullFromNetwork(chapter.url) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - } - - // Get the chapter images from network or disk - private Observable getPageImagesObservable() { - Observable pageObservable; - - if (!isDownloaded) { - pageObservable = source.getAllImageUrlsFromPageList(pageList) - .flatMap(source::getCachedImage, 2); - } else { - File chapterDir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter); - pageObservable = Observable.from(pageList) - .flatMap(page -> downloadManager.getDownloadedImage(page, chapterDir)); - } - return pageObservable.subscribeOn(Schedulers.io()) - .doOnCompleted(this::preloadNextChapter); + .observeOn(AndroidSchedulers.mainThread()) + ).map(pages -> { + for (Page page : pages) { + page.setChapter(chapter); + } + chapter.setPages(pages); + if (requestedPage >= -1 || currentPage == null) { + if (requestedPage == -1) { + currentPage = pages.get(pages.size() - 1); + } else { + currentPage = pages.get(requestedPage); + } + } + requestedPage = -2; + pageInitializerSubject.onNext(chapter); + return chapter; + }); } private Observable> getAdjacentChaptersObservable() { return Observable.zip( - db.getPreviousChapter(chapter).asRxObservable().take(1), - db.getNextChapter(chapter).asRxObservable().take(1), + db.getPreviousChapter(activeChapter).asRxObservable().take(1), + db.getNextChapter(activeChapter).asRxObservable().take(1), Pair::create) .doOnNext(pair -> { previousChapter = pair.first; @@ -164,22 +193,11 @@ public class ReaderPresenter extends BasePresenter { .observeOn(AndroidSchedulers.mainThread()); } - // Listen for retry page events - private Observable getRetryPageObservable() { - return retryPageSubject - .observeOn(Schedulers.io()) - .flatMap(page -> page.getImageUrl() == null ? - source.getImageUrlFromPage(page) : - Observable.just(page)) - .flatMap(source::getCachedImage); - } - - // Preload the first pages of the next chapter + // Preload the first pages of the next chapter. Only for non seamless mode private Observable getPreloadNextChapterObservable() { return source.getCachedPageListOrPullFromNetwork(nextChapter.url) .flatMap(pages -> { - nextChapterPageList = pages; - // Preload at most 5 pages + nextChapter.setPages(pages); int pagesToPreload = Math.min(pages.size(), 5); return Observable.from(pages).take(pagesToPreload); }) @@ -198,6 +216,7 @@ public class ReaderPresenter extends BasePresenter { private Observable> getMangaSyncObservable() { return db.getMangasSync(manga).asRxObservable() + .take(1) .doOnNext(mangaSync -> this.mangaSyncList = mangaSync); } @@ -207,24 +226,58 @@ public class ReaderPresenter extends BasePresenter { // Loads the given chapter private void loadChapter(Chapter chapter, int requestedPage) { - // Before loading the chapter, stop preloading (if it's working) and save current progress - stopPreloadingNextChapter(); + if (seamlessMode) { + if (appenderSubscription != null) + remove(appenderSubscription); + } else { + stopPreloadingNextChapter(); + } - this.chapter = chapter; - isDownloaded = isChapterDownloaded(chapter); + this.activeChapter = chapter; + chapter.status = isChapterDownloaded(chapter) ? Download.DOWNLOADED : Download.NOT_DOWNLOADED; // If the chapter is partially read, set the starting page to the last the user read if (!chapter.read && chapter.last_page_read != 0) - currentPage = chapter.last_page_read; + this.requestedPage = chapter.last_page_read; else - currentPage = requestedPage; + this.requestedPage = requestedPage; // Reset next and previous chapter. They have to be fetched again nextChapter = null; previousChapter = null; - nextChapterPageList = null; start(GET_PAGE_LIST); + start(GET_ADJACENT_CHAPTERS); + } + + public void setActiveChapter(Chapter chapter) { + onChapterLeft(true); // force markAsRead since at this point the current page is already for the next chapter + this.activeChapter = chapter; + nextChapter = null; + previousChapter = null; + start(GET_ADJACENT_CHAPTERS); + } + + public void appendNextChapter() { + if (nextChapter == null) + return; + + if (appenderSubscription != null) + remove(appenderSubscription); + + nextChapter.status = isChapterDownloaded(nextChapter) ? Download.DOWNLOADED : Download.NOT_DOWNLOADED; + + appenderSubscription = getPageListObservable(nextChapter) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(deliverLatestCache()) + .subscribe(split((view, chapter) -> { + view.onAppendChapter(chapter); + }, (view, error) -> { + view.onChapterAppendError(); + })); + + add(appenderSubscription); } // Check whether the given chapter is downloaded @@ -237,37 +290,38 @@ public class ReaderPresenter extends BasePresenter { retryPageSubject.onNext(page); } - // Called before loading another chapter or leaving the reader. It allows to do operations - // over the chapter read like saving progress public void onChapterLeft() { - if (pageList == null) - return; - - // Cache current page list progress for online chapters to allow a faster reopen - if (!isDownloaded) - source.savePageList(chapter.url, pageList); - - // Save current progress of the chapter. Mark as read if the chapter is finished - chapter.last_page_read = currentPage; - if (isChapterFinished()) { - chapter.read = true; - } - db.insertChapter(chapter).asRxObservable().subscribe(); + onChapterLeft(false); } - // Check whether the chapter has been read - private boolean isChapterFinished() { - return !chapter.read && currentPage == pageList.size() - 1; + // Called before loading another chapter or leaving the reader. It allows to do operations + // over the chapter read like saving progress + public void onChapterLeft(boolean forceMarkAsRead) { + if (activeChapter.getPages() == null) + return; + + Page activePage = getCurrentPage(); + + // Cache current page list progress for online chapters to allow a faster reopen + if (!activeChapter.isDownloaded()) + source.savePageList(activeChapter.url, activePage.getChapter().getPages()); + + // Save current progress of the chapter. Mark as read if the chapter is finished + activeChapter.last_page_read = activePage.getPageNumber(); + if (forceMarkAsRead || activePage.isLastPage()) { + activeChapter.read = true; + } + db.insertChapter(activeChapter).asRxObservable().subscribe(); } public int getMangaSyncChapterToUpdate() { - if (pageList == null || mangaSyncList == null || mangaSyncList.isEmpty()) + if (activeChapter.getPages() == null || mangaSyncList == null || mangaSyncList.isEmpty()) return 0; int lastChapterReadLocal = 0; // If the current chapter has been read, we check with this one - if (chapter.read) - lastChapterReadLocal = (int) Math.floor(chapter.chapter_number); + if (activeChapter.read) + lastChapterReadLocal = (int) Math.floor(activeChapter.chapter_number); // If not, we check if the previous chapter has been read else if (previousChapter != null && previousChapter.read) lastChapterReadLocal = (int) Math.floor(previousChapter.chapter_number); @@ -295,7 +349,7 @@ public class ReaderPresenter extends BasePresenter { } } - public void setCurrentPage(int currentPage) { + public void setCurrentPage(Page currentPage) { this.currentPage = currentPage; } @@ -334,8 +388,8 @@ public class ReaderPresenter extends BasePresenter { private void stopPreloadingNextChapter() { if (!isUnsubscribed(PRELOAD_NEXT_CHAPTER)) { stop(PRELOAD_NEXT_CHAPTER); - if (nextChapterPageList != null) - source.savePageList(nextChapter.url, nextChapterPageList); + if (nextChapter.getPages() != null) + source.savePageList(nextChapter.url, nextChapter.getPages()); } } @@ -348,4 +402,11 @@ public class ReaderPresenter extends BasePresenter { return manga; } + public Page getCurrentPage() { + return currentPage; + } + + public boolean isSeamlessMode() { + return seamlessMode; + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java index 71f069c9f..3a9a29e32 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java @@ -1,15 +1,15 @@ package eu.kanade.tachiyomi.ui.reader.viewer.base; -import android.view.MotionEvent; - import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder; import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder; import com.davemorrissey.labs.subscaleview.decoder.RapidImageRegionDecoder; import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder; import com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionDecoder; +import java.util.ArrayList; import java.util.List; +import eu.kanade.tachiyomi.data.database.models.Chapter; import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment; import eu.kanade.tachiyomi.ui.reader.ReaderActivity; @@ -18,40 +18,81 @@ public abstract class BaseReader extends BaseFragment { protected int currentPage; protected List pages; + protected List chapters; protected Class regionDecoderClass; protected Class bitmapDecoderClass; + private boolean hasRequestedNextChapter; + public static final int RAPID_DECODER = 0; public static final int SKIA_DECODER = 1; public void updatePageNumber() { - getReaderActivity().onPageChanged(getCurrentPage(), getTotalPages()); + getReaderActivity().onPageChanged(getCurrentPage().getPageNumber(), getCurrentPage().getChapter().getPages().size()); } - public int getCurrentPage() { - return currentPage; - } - - public int getPageForPosition(int position) { - return position; - } - - public int getPositionForPage(int page) { - return page; + public Page getCurrentPage() { + return pages.get(currentPage); } public void onPageChanged(int position) { - currentPage = getPageForPosition(position); + if (getReaderActivity().getPresenter().isSeamlessMode()) { + Chapter oldChapter = pages.get(currentPage).getChapter(); + Chapter newChapter = pages.get(position).getChapter(); + if (!hasRequestedNextChapter && position > pages.size() - 5) { + hasRequestedNextChapter = true; + getReaderActivity().getPresenter().appendNextChapter(); + } + if (!oldChapter.id.equals(newChapter.id)) { + Page page = pages.get(position); + onChapterChanged(page.getChapter(), page); + } + } + currentPage = position; updatePageNumber(); } - public int getTotalPages() { - return pages == null ? 0 : pages.size(); + private void onChapterChanged(Chapter chapter, Page currentPage) { + getReaderActivity().onEnterChapter(chapter, currentPage.getPageNumber()); + } + + public void setSelectedPage(Page page) { + setSelectedPage(getPageIndex(page)); + } + + public int getPageIndex(Page search) { + // search for the index of a page in the current list without requiring them to be the same object + for (Page page : pages) { + if (page.getPageNumber() == search.getPageNumber() && + page.getChapter().id.equals(search.getChapter().id)) { + return pages.indexOf(page); + } + } + return 0; + } + + public void onPageListReady(Chapter chapter, Page currentPage) { + if (chapters == null || !chapters.contains(chapter)) { + // if we reset the loaded page we also need to reset the loaded chapters + chapters = new ArrayList<>(); + chapters.add(chapter); + onSetChapter(chapter, currentPage); + } else { + setSelectedPage(currentPage); + } + } + + public void onPageListAppendReady(Chapter chapter) { + if (!chapters.contains(chapter)) { + hasRequestedNextChapter = false; + chapters.add(chapter); + onAppendChapter(chapter); + } } public abstract void setSelectedPage(int pageNumber); - public abstract void onPageListReady(List pages, int currentPage); - public abstract boolean onImageTouch(MotionEvent motionEvent); + public abstract void onSetChapter(Chapter chapter, Page currentPage); + public abstract void onAppendChapter(Chapter chapter); public void setDecoderClass(int value) { switch (value) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterSingleTapListener.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterSingleTapListener.java deleted file mode 100644 index 2f8e0cc60..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterSingleTapListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.viewer.base; - -public interface OnChapterSingleTapListener { - void onCenterTap(); - void onLeftSideTap(); - void onRightSideTap(); -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterBoundariesOutListener.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.java similarity index 68% rename from app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterBoundariesOutListener.java rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.java index 2870fdfe7..4de17802a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/OnChapterBoundariesOutListener.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.java @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.reader.viewer.base; +package eu.kanade.tachiyomi.ui.reader.viewer.pager; public interface OnChapterBoundariesOutListener { void onFirstPageOutEvent(); diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java index a9282a15e..a3186babb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java @@ -1,11 +1,8 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager; import android.support.v4.view.PagerAdapter; -import android.view.MotionEvent; import android.view.ViewGroup; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; import rx.functions.Action1; public interface Pager { @@ -24,13 +21,7 @@ public interface Pager { PagerAdapter getAdapter(); void setAdapter(PagerAdapter adapter); - boolean onImageTouch(MotionEvent motionEvent); - void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener); - void setOnChapterSingleTapListener(OnChapterSingleTapListener listener); - - OnChapterBoundariesOutListener getChapterBoundariesListener(); - OnChapterSingleTapListener getChapterSingleTapListener(); void setOnPageChangeListener(Action1 onPageChanged); void clearOnPageChangeListeners(); diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerGestureListener.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerGestureListener.java deleted file mode 100644 index bee01c590..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerGestureListener.java +++ /dev/null @@ -1,71 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.viewer.pager; - -import android.view.GestureDetector; -import android.view.MotionEvent; - -public class PagerGestureListener extends GestureDetector.SimpleOnGestureListener { - - private Pager pager; - - private static final float LEFT_REGION = 0.33f; - private static final float RIGHT_REGION = 0.66f; - - public PagerGestureListener(Pager pager) { - this.pager = pager; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - final int position = pager.getCurrentItem(); - final float positionX = e.getX(); - - if (positionX < pager.getWidth() * LEFT_REGION) { - if (position != 0) { - onLeftSideTap(); - } else { - onFirstPageOut(); - } - } else if (positionX > pager.getWidth() * RIGHT_REGION) { - if (position != pager.getAdapter().getCount() - 1) { - onRightSideTap(); - } else { - onLastPageOut(); - } - } else { - onCenterTap(); - } - - return true; - } - - private void onLeftSideTap() { - if (pager.getChapterSingleTapListener() != null) { - pager.getChapterSingleTapListener().onLeftSideTap(); - } - } - - private void onRightSideTap() { - if (pager.getChapterSingleTapListener() != null) { - pager.getChapterSingleTapListener().onRightSideTap(); - } - } - - private void onCenterTap() { - if (pager.getChapterSingleTapListener() != null) { - pager.getChapterSingleTapListener().onCenterTap(); - } - } - - private void onFirstPageOut() { - if (pager.getChapterBoundariesListener() != null) { - pager.getChapterBoundariesListener().onFirstPageOutEvent(); - } - } - - private void onLastPageOut() { - if (pager.getChapterBoundariesListener() != null) { - pager.getChapterBoundariesListener().onLastPageOutEvent(); - } - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java index 0bc556270..86d8b3e04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java @@ -1,16 +1,16 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager; +import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ViewGroup; -import java.util.List; +import java.util.ArrayList; import eu.kanade.tachiyomi.R; +import eu.kanade.tachiyomi.data.database.models.Chapter; import eu.kanade.tachiyomi.data.preference.PreferencesHelper; import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader; import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader; import rx.subscriptions.CompositeSubscription; @@ -21,8 +21,8 @@ public abstract class PagerReader extends BaseReader { protected PagerReaderAdapter adapter; protected Pager pager; + protected GestureDetector gestureDetector; - private boolean isReady; protected boolean transitions; protected CompositeSubscription subscriptions; @@ -34,6 +34,9 @@ public abstract class PagerReader extends BaseReader { public static final int ALIGN_RIGHT = 3; public static final int ALIGN_CENTER = 4; + private static final float LEFT_REGION = 0.33f; + private static final float RIGHT_REGION = 0.66f; + protected void initializePager(Pager pager) { this.pager = pager; pager.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); @@ -42,30 +45,15 @@ public abstract class PagerReader extends BaseReader { pager.setOnChapterBoundariesOutListener(new OnChapterBoundariesOutListener() { @Override public void onFirstPageOutEvent() { - onFirstPageOut(); + getReaderActivity().requestPreviousChapter(); } @Override public void onLastPageOutEvent() { - onLastPageOut(); - } - }); - pager.setOnChapterSingleTapListener(new OnChapterSingleTapListener() { - @Override - public void onCenterTap() { - getReaderActivity().onCenterSingleTap(); - } - - @Override - public void onLeftSideTap() { - pager.setCurrentItem(pager.getCurrentItem() - 1, transitions); - } - - @Override - public void onRightSideTap() { - pager.setCurrentItem(pager.getCurrentItem() + 1, transitions); + getReaderActivity().requestNextChapter(); } }); + gestureDetector = createGestureDetector(); adapter = new PagerReaderAdapter(getChildFragmentManager()); pager.setAdapter(adapter); @@ -77,28 +65,27 @@ public abstract class PagerReader extends BaseReader { .doOnNext(this::setDecoderClass) .skip(1) .distinctUntilChanged() - .subscribe(v -> adapter.notifyDataSetChanged())); + .subscribe(v -> pager.setAdapter(adapter))); subscriptions.add(preferences.imageScaleType() .asObservable() .doOnNext(this::setImageScaleType) .skip(1) .distinctUntilChanged() - .subscribe(v -> adapter.notifyDataSetChanged())); + .subscribe(v -> pager.setAdapter(adapter))); subscriptions.add(preferences.zoomStart() .asObservable() .doOnNext(this::setZoomStart) .skip(1) .distinctUntilChanged() - .subscribe(v -> adapter.notifyDataSetChanged())); + .subscribe(v -> pager.setAdapter(adapter))); subscriptions.add(preferences.enableTransitions() .asObservable() .subscribe(value -> transitions = value)); setPages(); - isReady = true; } @Override @@ -107,14 +94,41 @@ public abstract class PagerReader extends BaseReader { super.onDestroyView(); } - @Override - public void onPageListReady(List pages, int currentPage) { - if (this.pages != pages) { - this.pages = pages; - this.currentPage = currentPage; - if (isReady) { - setPages(); + protected GestureDetector createGestureDetector() { + return new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + final float positionX = e.getX(); + + if (positionX < pager.getWidth() * LEFT_REGION) { + onLeftSideTap(); + } else if (positionX > pager.getWidth() * RIGHT_REGION) { + onRightSideTap(); + } else { + getReaderActivity().onCenterSingleTap(); + } + return true; } + }); + } + + @Override + public void onSetChapter(Chapter chapter, Page currentPage) { + pages = new ArrayList<>(chapter.getPages()); + this.currentPage = getPageIndex(currentPage); // we might have a new page object + + // This method can be called before the view is created + if (pager != null) { + setPages(); + } + } + + public void onAppendChapter(Chapter chapter) { + pages.addAll(chapter.getPages()); + + // This method can be called before the view is created + if (pager != null) { + adapter.setPages(pages); } } @@ -130,12 +144,23 @@ public abstract class PagerReader extends BaseReader { @Override public void setSelectedPage(int pageNumber) { - pager.setCurrentItem(getPositionForPage(pageNumber), false); + pager.setCurrentItem(pageNumber, false); } - @Override - public boolean onImageTouch(MotionEvent motionEvent) { - return pager.onImageTouch(motionEvent); + protected void onLeftSideTap() { + if (pager.getCurrentItem() != 0) { + pager.setCurrentItem(pager.getCurrentItem() - 1, transitions); + } else { + getReaderActivity().requestPreviousChapter(); + } + } + + protected void onRightSideTap() { + if (pager.getCurrentItem() != pager.getAdapter().getCount() - 1) { + pager.setCurrentItem(pager.getCurrentItem() + 1, transitions); + } else { + getReaderActivity().requestNextChapter(); + } } private void setImageScaleType(int scaleType) { @@ -155,7 +180,4 @@ public abstract class PagerReader extends BaseReader { } } - public abstract void onFirstPageOut(); - public abstract void onLastPageOut(); - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.java index bef8ac7d8..bf84a25a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.java @@ -31,14 +31,10 @@ public class PagerReaderAdapter extends FragmentStatePagerAdapter { public Object instantiateItem(ViewGroup container, int position) { PagerReaderFragment f = (PagerReaderFragment) super.instantiateItem(container, position); f.setPage(pages.get(position)); + f.setPosition(position); return f; } - @Override - public int getItemPosition(Object object) { - return POSITION_NONE; - } - public List getPages() { return pages; } @@ -48,4 +44,17 @@ public class PagerReaderAdapter extends FragmentStatePagerAdapter { notifyDataSetChanged(); } + @Override + public int getItemPosition(Object object) { + PagerReaderFragment f = (PagerReaderFragment) object; + int position = f.getPosition(); + if (position >= 0 && position < getCount()) { + if (pages.get(position) == f.getPage()) { + return POSITION_UNCHANGED; + } else { + return POSITION_NONE; + } + } + return super.getItemPosition(object); + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java index fa92e8c44..19e85f961 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java @@ -26,6 +26,7 @@ import eu.kanade.tachiyomi.R; import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment; import eu.kanade.tachiyomi.ui.reader.ReaderActivity; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader; import eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader; import rx.Observable; import rx.Subscription; @@ -42,9 +43,12 @@ public class PagerReaderFragment extends BaseFragment { @Bind(R.id.retry_button) Button retryButton; private Page page; - private boolean isReady; private Subscription progressSubscription; private Subscription statusSubscription; + private int position = -1; + + private int lightGreyColor; + private int blackColor; public static PagerReaderFragment newInstance() { return new PagerReaderFragment(); @@ -57,8 +61,15 @@ public class PagerReaderFragment extends BaseFragment { ReaderActivity activity = getReaderActivity(); PagerReader parentFragment = (PagerReader) getParentFragment(); + lightGreyColor = ContextCompat.getColor(getContext(), R.color.light_grey); + blackColor = ContextCompat.getColor(getContext(), R.color.primary_text); + if (activity.getReaderTheme() == ReaderActivity.BLACK_THEME) { - progressText.setTextColor(ContextCompat.getColor(getContext(), R.color.light_grey)); + progressText.setTextColor(lightGreyColor); + } + + if (parentFragment instanceof RightToLeftReader) { + view.setRotation(-180); } imageView.setParallelLoadingEnabled(true); @@ -69,7 +80,7 @@ public class PagerReaderFragment extends BaseFragment { imageView.setRegionDecoderClass(parentFragment.getRegionDecoderClass()); imageView.setBitmapDecoderClass(parentFragment.getBitmapDecoderClass()); imageView.setVerticalScrollingParent(parentFragment instanceof VerticalReader); - imageView.setOnTouchListener((v, motionEvent) -> parentFragment.onImageTouch(motionEvent)); + imageView.setOnTouchListener((v, motionEvent) -> parentFragment.gestureDetector.onTouchEvent(motionEvent)); imageView.setOnImageEventListener(new SubsamplingScaleImageView.DefaultOnImageEventListener() { @Override public void onReady() { @@ -103,7 +114,6 @@ public class PagerReaderFragment extends BaseFragment { }); observeStatus(); - isReady = true; return view; } @@ -111,6 +121,7 @@ public class PagerReaderFragment extends BaseFragment { public void onDestroyView() { unsubscribeProgress(); unsubscribeStatus(); + imageView.setOnTouchListener(null); imageView.setOnImageEventListener(null); ButterKnife.unbind(this); super.onDestroyView(); @@ -118,11 +129,17 @@ public class PagerReaderFragment extends BaseFragment { public void setPage(Page page) { this.page = page; - if (isReady) { + + // This method can be called before the view is created + if (imageView != null) { observeStatus(); } } + public void setPosition(int position) { + this.position = position; + } + private void showImage() { if (page == null || page.getImagePath() == null) return; @@ -160,8 +177,7 @@ public class PagerReaderFragment extends BaseFragment { errorText.setGravity(Gravity.CENTER); errorText.setText(R.string.decode_image_error); errorText.setTextColor(getReaderActivity().getReaderTheme() == ReaderActivity.BLACK_THEME ? - ContextCompat.getColor(getContext(), R.color.light_grey) : - ContextCompat.getColor(getContext(), R.color.primary_text)); + lightGreyColor : blackColor); view.addView(errorText); } @@ -236,6 +252,14 @@ public class PagerReaderFragment extends BaseFragment { } } + public Page getPage() { + return page; + } + + public int getPosition() { + return position; + } + private ReaderActivity getReaderActivity() { return (ReaderActivity) getActivity(); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java index d842ca360..4d68990c2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java @@ -2,38 +2,21 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal; import android.content.Context; import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.GestureDetector; import android.view.MotionEvent; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.OnChapterBoundariesOutListener; import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager; -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import rx.functions.Action1; public class HorizontalPager extends ViewPager implements Pager { - private GestureDetector gestureDetector; - private OnChapterBoundariesOutListener onChapterBoundariesOutListener; - private OnChapterSingleTapListener onChapterSingleTapListener; private static final float SWIPE_TOLERANCE = 0.25f; private float startDragX; public HorizontalPager(Context context) { super(context); - init(context); - } - - public HorizontalPager(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - private void init(Context context) { - gestureDetector = new GestureDetector(context, new PagerGestureListener(this)); } @Override @@ -86,31 +69,11 @@ public class HorizontalPager extends ViewPager implements Pager { } } - @Override - public boolean onImageTouch(MotionEvent event) { - return gestureDetector.onTouchEvent(event); - } - @Override public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) { onChapterBoundariesOutListener = listener; } - @Override - public void setOnChapterSingleTapListener(OnChapterSingleTapListener listener) { - onChapterSingleTapListener = listener; - } - - @Override - public OnChapterBoundariesOutListener getChapterBoundariesListener() { - return onChapterBoundariesOutListener; - } - - @Override - public OnChapterSingleTapListener getChapterSingleTapListener() { - return onChapterSingleTapListener; - } - @Override public void setOnPageChangeListener(Action1 function) { addOnPageChangeListener(new SimpleOnPageChangeListener() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalReader.java deleted file mode 100644 index 109a989ed..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalReader.java +++ /dev/null @@ -1,19 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerReader; - -public abstract class HorizontalReader extends PagerReader { - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { - HorizontalPager pager = new HorizontalPager(getActivity()); - initializePager(pager); - return pager; - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.java index ac0a3312a..faa7d5c80 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.java @@ -1,15 +1,19 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal; -public class LeftToRightReader extends HorizontalReader { +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerReader; + +public class LeftToRightReader extends PagerReader { @Override - public void onFirstPageOut() { - getReaderActivity().requestPreviousChapter(); - } - - @Override - public void onLastPageOut() { - getReaderActivity().requestNextChapter(); + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { + HorizontalPager pager = new HorizontalPager(getActivity()); + initializePager(pager); + return pager; } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.java index 75b25c933..3ae824648 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.java @@ -1,38 +1,30 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -import eu.kanade.tachiyomi.data.source.model.Page; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerReader; -public class RightToLeftReader extends HorizontalReader { +public class RightToLeftReader extends PagerReader { @Override - public void onPageListReady(List pages, int currentPage) { - ArrayList inversedPages = new ArrayList<>(pages); - Collections.reverse(inversedPages); - super.onPageListReady(inversedPages, currentPage); + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { + HorizontalPager pager = new HorizontalPager(getActivity()); + pager.setRotation(180); + initializePager(pager); + return pager; } @Override - public int getPageForPosition(int position) { - return (getTotalPages() - 1) - position; + protected void onLeftSideTap() { + super.onRightSideTap(); } @Override - public int getPositionForPage(int page) { - return (getTotalPages() - 1) - page; - } - - @Override - public void onFirstPageOut() { - getReaderActivity().requestNextChapter(); - } - - @Override - public void onLastPageOut() { - getReaderActivity().requestPreviousChapter(); + protected void onRightSideTap() { + super.onLeftSideTap(); } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java index ec4ec4790..52892ac66 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java @@ -1,38 +1,21 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical; import android.content.Context; -import android.util.AttributeSet; -import android.view.GestureDetector; import android.view.MotionEvent; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; -import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.OnChapterBoundariesOutListener; import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager; -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import rx.functions.Action1; public class VerticalPager extends VerticalViewPagerImpl implements Pager { - private GestureDetector gestureDetector; - private OnChapterBoundariesOutListener onChapterBoundariesOutListener; - private OnChapterSingleTapListener onChapterSingleTapListener; private static final float SWIPE_TOLERANCE = 0.25f; private float startDragY; public VerticalPager(Context context) { super(context); - init(context); - } - - public VerticalPager(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - private void init(Context context) { - gestureDetector = new GestureDetector(context, new PagerGestureListener(this)); } @Override @@ -85,31 +68,11 @@ public class VerticalPager extends VerticalViewPagerImpl implements Pager { } } - @Override - public boolean onImageTouch(MotionEvent event) { - return gestureDetector.onTouchEvent(event); - } - @Override public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) { onChapterBoundariesOutListener = listener; } - @Override - public void setOnChapterSingleTapListener(OnChapterSingleTapListener listener) { - onChapterSingleTapListener = listener; - } - - @Override - public OnChapterBoundariesOutListener getChapterBoundariesListener() { - return onChapterBoundariesOutListener; - } - - @Override - public OnChapterSingleTapListener getChapterSingleTapListener() { - return onChapterSingleTapListener; - } - @Override public void setOnPageChangeListener(Action1 function) { addOnPageChangeListener(new SimpleOnPageChangeListener() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.java index 55d917f3c..635032209 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.java @@ -16,14 +16,4 @@ public class VerticalReader extends PagerReader { return pager; } - @Override - public void onFirstPageOut() { - getReaderActivity().requestPreviousChapter(); - } - - @Override - public void onLastPageOut() { - getReaderActivity().requestNextChapter(); - } - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.java index 780e8c1e7..4bab8228d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.java @@ -21,7 +21,7 @@ public class WebtoonAdapter extends RecyclerView.Adapter { public WebtoonAdapter(WebtoonReader fragment) { this.fragment = fragment; pages = new ArrayList<>(); - touchListener = (v, event) -> fragment.onImageTouch(event); + touchListener = (v, event) -> fragment.gestureDetector.onTouchEvent(event); } public Page getItem(int position) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java index 2c1803089..0d987184d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java @@ -8,8 +8,9 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import java.util.List; +import java.util.ArrayList; +import eu.kanade.tachiyomi.data.database.models.Chapter; import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader; import eu.kanade.tachiyomi.widget.PreCachingLayoutManager; @@ -27,12 +28,11 @@ public class WebtoonReader extends BaseReader { private PreCachingLayoutManager layoutManager; private Subscription subscription; private Subscription decoderSubscription; - private GestureDetector gestureDetector; + protected GestureDetector gestureDetector; - private boolean isReady; private int scrollDistance; - private static final String SCROLL_STATE = "scroll_state"; + private static final String SAVED_POSITION = "saved_position"; private static final float LEFT_REGION = 0.33f; private static final float RIGHT_REGION = 0.66f; @@ -47,7 +47,7 @@ public class WebtoonReader extends BaseReader { layoutManager = new PreCachingLayoutManager(getActivity()); layoutManager.setExtraLayoutSpace(screenHeight / 2); if (savedState != null) { - layoutManager.onRestoreInstanceState(savedState.getParcelable(SCROLL_STATE)); + layoutManager.scrollToPositionWithOffset(savedState.getInt(SAVED_POSITION), 0); } recycler = new RecyclerView(getActivity()); @@ -80,8 +80,6 @@ public class WebtoonReader extends BaseReader { }); setPages(); - isReady = true; - return recycler; } @@ -100,7 +98,9 @@ public class WebtoonReader extends BaseReader { @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putParcelable(SCROLL_STATE, layoutManager.onSaveInstanceState()); + int savedPosition = pages != null ? + pages.get(layoutManager.findFirstVisibleItemPosition()).getPageNumber() : 0; + outState.putInt(SAVED_POSITION, savedPosition); } private void unsubscribeStatus() { @@ -110,18 +110,30 @@ public class WebtoonReader extends BaseReader { @Override public void setSelectedPage(int pageNumber) { - recycler.scrollToPosition(getPositionForPage(pageNumber)); + recycler.scrollToPosition(pageNumber); } @Override - public void onPageListReady(List pages, int currentPage) { - if (this.pages != pages) { - this.pages = pages; - // Restoring current page is not supported. It's getting weird scrolling jumps - // this.currentPage = currentPage; - if (isReady) { - setPages(); - } + public void onSetChapter(Chapter chapter, Page currentPage) { + pages = new ArrayList<>(chapter.getPages()); + // Restoring current page is not supported. It's getting weird scrolling jumps + // this.currentPage = currentPage; + + // This method can be called before the view is created + if (recycler != null) { + setPages(); + } + } + + @Override + public void onAppendChapter(Chapter chapter) { + int insertStart = pages.size(); + pages.addAll(chapter.getPages()); + + // This method can be called before the view is created + if (recycler != null) { + adapter.setPages(pages); + adapter.notifyItemRangeInserted(insertStart, chapter.getPages().size()); } } @@ -141,19 +153,14 @@ public class WebtoonReader extends BaseReader { recycler.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - - currentPage = layoutManager.findLastVisibleItemPosition(); - updatePageNumber(); + int page = layoutManager.findLastVisibleItemPosition(); + if (page != currentPage) { + onPageChanged(page); + } } }); } - @Override - public boolean onImageTouch(MotionEvent motionEvent) { - return gestureDetector.onTouchEvent(motionEvent); - } - private void observeStatus(int position) { if (position == pages.size()) return; diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index ff88227f2..b827b2bf3 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -27,6 +27,7 @@ pref_custom_brightness_value_key pref_reader_theme_key pref_image_decoder_key + pref_seamless_mode_key pref_download_directory_key pref_download_slots_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b3ee4d191..17bb6d271 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,6 +84,7 @@ Enable transitions Show page number Use custom brightness + Enable seamless chapter transitions Keep screen on Background color White diff --git a/app/src/main/res/xml/pref_reader.xml b/app/src/main/res/xml/pref_reader.xml index 35fe58f3b..9c33747e5 100644 --- a/app/src/main/res/xml/pref_reader.xml +++ b/app/src/main/res/xml/pref_reader.xml @@ -21,6 +21,10 @@ android:key="@string/pref_custom_brightness_key" android:defaultValue="false" /> + +