mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-11 12:30:49 +01:00
seamless chapter transitions
This commit is contained in:
parent
16081817c2
commit
2566862e0f
25 changed files with 463 additions and 428 deletions
|
@ -4,8 +4,11 @@ import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
|
||||||
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
|
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable;
|
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;
|
import eu.kanade.tachiyomi.util.UrlUtil;
|
||||||
|
|
||||||
@StorIOSQLiteType(table = ChapterTable.TABLE)
|
@StorIOSQLiteType(table = ChapterTable.TABLE)
|
||||||
|
@ -40,6 +43,8 @@ public class Chapter implements Serializable {
|
||||||
|
|
||||||
public int status;
|
public int status;
|
||||||
|
|
||||||
|
private transient List<Page> pages;
|
||||||
|
|
||||||
public Chapter() {}
|
public Chapter() {}
|
||||||
|
|
||||||
public void setUrl(String url) {
|
public void setUrl(String url) {
|
||||||
|
@ -68,4 +73,15 @@ public class Chapter implements Serializable {
|
||||||
return chapter;
|
return chapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Page> getPages() {
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPages(List<Page> pages) {
|
||||||
|
this.pages = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDownloaded() {
|
||||||
|
return status == Download.DOWNLOADED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,10 @@ public class PreferencesHelper {
|
||||||
return rxPrefs.getInteger(getKey(R.string.pref_last_catalogue_source_key), -1);
|
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<Boolean> catalogueAsList() {
|
public Preference<Boolean> catalogueAsList() {
|
||||||
return rxPrefs.getBoolean(getKey(R.string.pref_display_catalogue_as_list), false);
|
return rxPrefs.getBoolean(getKey(R.string.pref_display_catalogue_as_list), false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package eu.kanade.tachiyomi.data.source.model;
|
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 eu.kanade.tachiyomi.data.network.ProgressListener;
|
||||||
import rx.subjects.PublishSubject;
|
import rx.subjects.PublishSubject;
|
||||||
|
|
||||||
|
@ -8,6 +12,7 @@ public class Page implements ProgressListener {
|
||||||
private int pageNumber;
|
private int pageNumber;
|
||||||
private String url;
|
private String url;
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
private transient Chapter chapter;
|
||||||
private transient String imagePath;
|
private transient String imagePath;
|
||||||
private transient volatile int status;
|
private transient volatile int status;
|
||||||
private transient volatile int progress;
|
private transient volatile int progress;
|
||||||
|
@ -82,4 +87,16 @@ public class Page implements ProgressListener {
|
||||||
this.statusSubject = subject;
|
this.statusSubject = subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Chapter getChapter() {
|
||||||
|
return chapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChapter(Chapter chapter) {
|
||||||
|
this.chapter = chapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLastPage() {
|
||||||
|
List<Page> chapterPages = chapter.getPages();
|
||||||
|
return chapterPages.size() -1 == pageNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,16 +158,34 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
|
||||||
ToastUtil.showShort(this, R.string.page_list_error);
|
ToastUtil.showShort(this, R.string.page_list_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onChapterReady(List<Page> pages, Manga manga, Chapter chapter, int currentPage) {
|
public void onChapterAppendError() {
|
||||||
if (currentPage == -1) {
|
// Ignore
|
||||||
currentPage = pages.size() - 1;
|
}
|
||||||
|
|
||||||
|
public void onChapterReady(Manga manga, Chapter chapter, Page currentPage) {
|
||||||
|
List<Page> pages = chapter.getPages();
|
||||||
|
if (currentPage == null) {
|
||||||
|
currentPage = pages.get(pages.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewer == null) {
|
if (viewer == null) {
|
||||||
viewer = getOrCreateViewer(manga);
|
viewer = getOrCreateViewer(manga);
|
||||||
}
|
}
|
||||||
viewer.onPageListReady(pages, currentPage);
|
viewer.onPageListReady(chapter, currentPage);
|
||||||
readerMenu.onChapterReady(pages.size(), manga, 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) {
|
public void onAdjacentChapters(Chapter previous, Chapter next) {
|
||||||
|
@ -209,8 +227,9 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
|
||||||
readerMenu.onPageChanged(currentPageIndex);
|
readerMenu.onPageChanged(currentPageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedPage(int pageIndex) {
|
public void gotoPageInCurrentChapter(int pageIndex) {
|
||||||
viewer.setSelectedPage(pageIndex);
|
Page requestedPage = viewer.getCurrentPage().getChapter().getPages().get(pageIndex);
|
||||||
|
viewer.setSelectedPage(requestedPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCenterSingleTap() {
|
public void onCenterSingleTap() {
|
||||||
|
@ -218,7 +237,7 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestNextChapter() {
|
public void requestNextChapter() {
|
||||||
getPresenter().setCurrentPage(viewer != null ? viewer.getCurrentPage() : 0);
|
getPresenter().setCurrentPage(viewer.getCurrentPage());
|
||||||
if (!getPresenter().loadNextChapter()) {
|
if (!getPresenter().loadNextChapter()) {
|
||||||
ToastUtil.showShort(this, R.string.no_next_chapter);
|
ToastUtil.showShort(this, R.string.no_next_chapter);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +245,7 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestPreviousChapter() {
|
public void requestPreviousChapter() {
|
||||||
getPresenter().setCurrentPage(viewer != null ? viewer.getCurrentPage() : 0);
|
getPresenter().setCurrentPage(viewer.getCurrentPage());
|
||||||
if (!getPresenter().loadPreviousChapter()) {
|
if (!getPresenter().loadPreviousChapter()) {
|
||||||
ToastUtil.showShort(this, R.string.no_previous_chapter);
|
ToastUtil.showShort(this, R.string.no_previous_chapter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ public class ReaderMenu {
|
||||||
return true;
|
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) {
|
if (manga.viewer == ReaderActivity.RIGHT_TO_LEFT && !inverted) {
|
||||||
// Invert the seekbar and textview fields for the right to left reader
|
// Invert the seekbar and textview fields for the right to left reader
|
||||||
seekBar.setRotation(180);
|
seekBar.setRotation(180);
|
||||||
|
@ -144,14 +144,17 @@ public class ReaderMenu {
|
||||||
// Don't invert again on chapter change
|
// Don't invert again on chapter change
|
||||||
inverted = true;
|
inverted = true;
|
||||||
}
|
}
|
||||||
|
activity.setToolbarTitle(manga.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveChapter(Chapter chapter, int currentPageIndex) {
|
||||||
// Set initial values
|
// Set initial values
|
||||||
|
int numPages = chapter.getPages().size();
|
||||||
totalPages.setText("" + numPages);
|
totalPages.setText("" + numPages);
|
||||||
currentPage.setText("" + (currentPageIndex + 1));
|
currentPage.setText("" + (currentPageIndex + 1));
|
||||||
seekBar.setMax(numPages - 1);
|
seekBar.setMax(numPages - 1);
|
||||||
seekBar.setProgress(currentPageIndex);
|
seekBar.setProgress(currentPageIndex);
|
||||||
|
|
||||||
activity.setToolbarTitle(manga.title);
|
|
||||||
activity.setToolbarSubtitle(chapter.chapter_number != -1 ?
|
activity.setToolbarSubtitle(chapter.chapter_number != -1 ?
|
||||||
activity.getString(R.string.chapter_subtitle,
|
activity.getString(R.string.chapter_subtitle,
|
||||||
decimalFormat.format(chapter.chapter_number)) :
|
decimalFormat.format(chapter.chapter_number)) :
|
||||||
|
@ -353,7 +356,7 @@ public class ReaderMenu {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
activity.setSelectedPage(progress);
|
activity.gotoPageInCurrentChapter(progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.Manga;
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaSync;
|
import eu.kanade.tachiyomi.data.database.models.MangaSync;
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager;
|
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.MangaSyncManager;
|
||||||
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService;
|
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService;
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
|
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 eu.kanade.tachiyomi.util.EventBusHook;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
import rx.Subscription;
|
||||||
import rx.android.schedulers.AndroidSchedulers;
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
import rx.schedulers.Schedulers;
|
import rx.schedulers.Schedulers;
|
||||||
import rx.subjects.PublishSubject;
|
import rx.subjects.PublishSubject;
|
||||||
|
@ -41,25 +43,25 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
@Inject SourceManager sourceManager;
|
@Inject SourceManager sourceManager;
|
||||||
|
|
||||||
@State Manga manga;
|
@State Manga manga;
|
||||||
@State Chapter chapter;
|
@State Chapter activeChapter;
|
||||||
@State int sourceId;
|
@State int sourceId;
|
||||||
@State boolean isDownloaded;
|
@State int requestedPage;
|
||||||
@State int currentPage;
|
private Page currentPage;
|
||||||
private Source source;
|
private Source source;
|
||||||
private Chapter nextChapter;
|
private Chapter nextChapter;
|
||||||
private Chapter previousChapter;
|
private Chapter previousChapter;
|
||||||
private List<Page> pageList;
|
|
||||||
private List<Page> nextChapterPageList;
|
|
||||||
private List<MangaSync> mangaSyncList;
|
private List<MangaSync> mangaSyncList;
|
||||||
|
|
||||||
private PublishSubject<Page> retryPageSubject;
|
private PublishSubject<Page> retryPageSubject;
|
||||||
|
private PublishSubject<Chapter> pageInitializerSubject;
|
||||||
|
|
||||||
|
private boolean seamlessMode;
|
||||||
|
private Subscription appenderSubscription;
|
||||||
|
|
||||||
private static final int GET_PAGE_LIST = 1;
|
private static final int GET_PAGE_LIST = 1;
|
||||||
private static final int GET_PAGE_IMAGES = 2;
|
private static final int GET_ADJACENT_CHAPTERS = 2;
|
||||||
private static final int GET_ADJACENT_CHAPTERS = 3;
|
private static final int GET_MANGA_SYNC = 3;
|
||||||
private static final int RETRY_IMAGES = 4;
|
private static final int PRELOAD_NEXT_CHAPTER = 4;
|
||||||
private static final int PRELOAD_NEXT_CHAPTER = 5;
|
|
||||||
private static final int GET_MANGA_SYNC = 6;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedState) {
|
protected void onCreate(Bundle savedState) {
|
||||||
|
@ -67,38 +69,29 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
|
|
||||||
if (savedState != null) {
|
if (savedState != null) {
|
||||||
source = sourceManager.get(sourceId);
|
source = sourceManager.get(sourceId);
|
||||||
|
initializeSubjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
retryPageSubject = PublishSubject.create();
|
seamlessMode = prefs.seamlessMode();
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
startableLatestCache(GET_ADJACENT_CHAPTERS, this::getAdjacentChaptersObservable,
|
startableLatestCache(GET_ADJACENT_CHAPTERS, this::getAdjacentChaptersObservable,
|
||||||
(view, pair) -> view.onAdjacentChapters(pair.first, pair.second));
|
(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());
|
restartable(GET_MANGA_SYNC, () -> getMangaSyncObservable().subscribe());
|
||||||
|
|
||||||
restartableLatestCache(GET_PAGE_LIST,
|
restartableLatestCache(GET_PAGE_LIST,
|
||||||
() -> getPageListObservable()
|
() -> getPageListObservable(activeChapter),
|
||||||
.doOnNext(pages -> pageList = pages)
|
(view, chapter) -> view.onChapterReady(manga, activeChapter, currentPage),
|
||||||
.doOnCompleted(() -> {
|
|
||||||
start(GET_ADJACENT_CHAPTERS);
|
|
||||||
start(GET_PAGE_IMAGES);
|
|
||||||
start(RETRY_IMAGES);
|
|
||||||
}),
|
|
||||||
(view, pages) -> view.onChapterReady(pages, manga, chapter, currentPage),
|
|
||||||
(view, error) -> view.onChapterError());
|
(view, error) -> view.onChapterError());
|
||||||
|
|
||||||
|
if (savedState == null) {
|
||||||
registerForStickyEvents();
|
registerForStickyEvents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -119,43 +112,79 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
manga = event.getManga();
|
manga = event.getManga();
|
||||||
source = event.getSource();
|
source = event.getSource();
|
||||||
sourceId = source.getId();
|
sourceId = source.getId();
|
||||||
|
initializeSubjects();
|
||||||
loadChapter(event.getChapter());
|
loadChapter(event.getChapter());
|
||||||
if (prefs.autoUpdateMangaSync()) {
|
if (prefs.autoUpdateMangaSync()) {
|
||||||
start(GET_MANGA_SYNC);
|
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
|
// Returns the page list of a chapter
|
||||||
private Observable<List<Page>> getPageListObservable() {
|
private Observable<Chapter> getPageListObservable(Chapter chapter) {
|
||||||
return isDownloaded ?
|
return (chapter.isDownloaded() ?
|
||||||
// Fetch the page list from disk
|
// Fetch the page list from disk
|
||||||
Observable.just(downloadManager.getSavedPageList(source, manga, chapter)) :
|
Observable.just(downloadManager.getSavedPageList(source, manga, chapter)) :
|
||||||
// Fetch the page list from cache or fallback to network
|
// Fetch the page list from cache or fallback to network
|
||||||
source.getCachedPageListOrPullFromNetwork(chapter.url)
|
source.getCachedPageListOrPullFromNetwork(chapter.url)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
}
|
).map(pages -> {
|
||||||
|
for (Page page : pages) {
|
||||||
// Get the chapter images from network or disk
|
page.setChapter(chapter);
|
||||||
private Observable<Page> getPageImagesObservable() {
|
}
|
||||||
Observable<Page> pageObservable;
|
chapter.setPages(pages);
|
||||||
|
if (requestedPage >= -1 || currentPage == null) {
|
||||||
if (!isDownloaded) {
|
if (requestedPage == -1) {
|
||||||
pageObservable = source.getAllImageUrlsFromPageList(pageList)
|
currentPage = pages.get(pages.size() - 1);
|
||||||
.flatMap(source::getCachedImage, 2);
|
} else {
|
||||||
} else {
|
currentPage = pages.get(requestedPage);
|
||||||
File chapterDir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter);
|
}
|
||||||
pageObservable = Observable.from(pageList)
|
}
|
||||||
.flatMap(page -> downloadManager.getDownloadedImage(page, chapterDir));
|
requestedPage = -2;
|
||||||
}
|
pageInitializerSubject.onNext(chapter);
|
||||||
return pageObservable.subscribeOn(Schedulers.io())
|
return chapter;
|
||||||
.doOnCompleted(this::preloadNextChapter);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Observable<Pair<Chapter, Chapter>> getAdjacentChaptersObservable() {
|
private Observable<Pair<Chapter, Chapter>> getAdjacentChaptersObservable() {
|
||||||
return Observable.zip(
|
return Observable.zip(
|
||||||
db.getPreviousChapter(chapter).asRxObservable().take(1),
|
db.getPreviousChapter(activeChapter).asRxObservable().take(1),
|
||||||
db.getNextChapter(chapter).asRxObservable().take(1),
|
db.getNextChapter(activeChapter).asRxObservable().take(1),
|
||||||
Pair::create)
|
Pair::create)
|
||||||
.doOnNext(pair -> {
|
.doOnNext(pair -> {
|
||||||
previousChapter = pair.first;
|
previousChapter = pair.first;
|
||||||
|
@ -164,22 +193,11 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for retry page events
|
// Preload the first pages of the next chapter. Only for non seamless mode
|
||||||
private Observable<Page> 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
|
|
||||||
private Observable<Page> getPreloadNextChapterObservable() {
|
private Observable<Page> getPreloadNextChapterObservable() {
|
||||||
return source.getCachedPageListOrPullFromNetwork(nextChapter.url)
|
return source.getCachedPageListOrPullFromNetwork(nextChapter.url)
|
||||||
.flatMap(pages -> {
|
.flatMap(pages -> {
|
||||||
nextChapterPageList = pages;
|
nextChapter.setPages(pages);
|
||||||
// Preload at most 5 pages
|
|
||||||
int pagesToPreload = Math.min(pages.size(), 5);
|
int pagesToPreload = Math.min(pages.size(), 5);
|
||||||
return Observable.from(pages).take(pagesToPreload);
|
return Observable.from(pages).take(pagesToPreload);
|
||||||
})
|
})
|
||||||
|
@ -198,6 +216,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
|
|
||||||
private Observable<List<MangaSync>> getMangaSyncObservable() {
|
private Observable<List<MangaSync>> getMangaSyncObservable() {
|
||||||
return db.getMangasSync(manga).asRxObservable()
|
return db.getMangasSync(manga).asRxObservable()
|
||||||
|
.take(1)
|
||||||
.doOnNext(mangaSync -> this.mangaSyncList = mangaSync);
|
.doOnNext(mangaSync -> this.mangaSyncList = mangaSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,24 +226,58 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
|
|
||||||
// Loads the given chapter
|
// Loads the given chapter
|
||||||
private void loadChapter(Chapter chapter, int requestedPage) {
|
private void loadChapter(Chapter chapter, int requestedPage) {
|
||||||
// Before loading the chapter, stop preloading (if it's working) and save current progress
|
if (seamlessMode) {
|
||||||
stopPreloadingNextChapter();
|
if (appenderSubscription != null)
|
||||||
|
remove(appenderSubscription);
|
||||||
|
} else {
|
||||||
|
stopPreloadingNextChapter();
|
||||||
|
}
|
||||||
|
|
||||||
this.chapter = chapter;
|
this.activeChapter = chapter;
|
||||||
isDownloaded = isChapterDownloaded(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 the chapter is partially read, set the starting page to the last the user read
|
||||||
if (!chapter.read && chapter.last_page_read != 0)
|
if (!chapter.read && chapter.last_page_read != 0)
|
||||||
currentPage = chapter.last_page_read;
|
this.requestedPage = chapter.last_page_read;
|
||||||
else
|
else
|
||||||
currentPage = requestedPage;
|
this.requestedPage = requestedPage;
|
||||||
|
|
||||||
// Reset next and previous chapter. They have to be fetched again
|
// Reset next and previous chapter. They have to be fetched again
|
||||||
nextChapter = null;
|
nextChapter = null;
|
||||||
previousChapter = null;
|
previousChapter = null;
|
||||||
nextChapterPageList = null;
|
|
||||||
|
|
||||||
start(GET_PAGE_LIST);
|
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
|
// Check whether the given chapter is downloaded
|
||||||
|
@ -237,37 +290,38 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
retryPageSubject.onNext(page);
|
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() {
|
public void onChapterLeft() {
|
||||||
if (pageList == null)
|
onChapterLeft(false);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the chapter has been read
|
// Called before loading another chapter or leaving the reader. It allows to do operations
|
||||||
private boolean isChapterFinished() {
|
// over the chapter read like saving progress
|
||||||
return !chapter.read && currentPage == pageList.size() - 1;
|
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() {
|
public int getMangaSyncChapterToUpdate() {
|
||||||
if (pageList == null || mangaSyncList == null || mangaSyncList.isEmpty())
|
if (activeChapter.getPages() == null || mangaSyncList == null || mangaSyncList.isEmpty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int lastChapterReadLocal = 0;
|
int lastChapterReadLocal = 0;
|
||||||
// If the current chapter has been read, we check with this one
|
// If the current chapter has been read, we check with this one
|
||||||
if (chapter.read)
|
if (activeChapter.read)
|
||||||
lastChapterReadLocal = (int) Math.floor(chapter.chapter_number);
|
lastChapterReadLocal = (int) Math.floor(activeChapter.chapter_number);
|
||||||
// If not, we check if the previous chapter has been read
|
// If not, we check if the previous chapter has been read
|
||||||
else if (previousChapter != null && previousChapter.read)
|
else if (previousChapter != null && previousChapter.read)
|
||||||
lastChapterReadLocal = (int) Math.floor(previousChapter.chapter_number);
|
lastChapterReadLocal = (int) Math.floor(previousChapter.chapter_number);
|
||||||
|
@ -295,7 +349,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentPage(int currentPage) {
|
public void setCurrentPage(Page currentPage) {
|
||||||
this.currentPage = currentPage;
|
this.currentPage = currentPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,8 +388,8 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
private void stopPreloadingNextChapter() {
|
private void stopPreloadingNextChapter() {
|
||||||
if (!isUnsubscribed(PRELOAD_NEXT_CHAPTER)) {
|
if (!isUnsubscribed(PRELOAD_NEXT_CHAPTER)) {
|
||||||
stop(PRELOAD_NEXT_CHAPTER);
|
stop(PRELOAD_NEXT_CHAPTER);
|
||||||
if (nextChapterPageList != null)
|
if (nextChapter.getPages() != null)
|
||||||
source.savePageList(nextChapter.url, nextChapterPageList);
|
source.savePageList(nextChapter.url, nextChapter.getPages());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,4 +402,11 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Page getCurrentPage() {
|
||||||
|
return currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSeamlessMode() {
|
||||||
|
return seamlessMode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.base;
|
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.ImageDecoder;
|
||||||
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
|
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
|
||||||
import com.davemorrissey.labs.subscaleview.decoder.RapidImageRegionDecoder;
|
import com.davemorrissey.labs.subscaleview.decoder.RapidImageRegionDecoder;
|
||||||
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder;
|
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder;
|
||||||
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionDecoder;
|
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionDecoder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page;
|
import eu.kanade.tachiyomi.data.source.model.Page;
|
||||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment;
|
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment;
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
||||||
|
@ -18,40 +18,81 @@ public abstract class BaseReader extends BaseFragment {
|
||||||
|
|
||||||
protected int currentPage;
|
protected int currentPage;
|
||||||
protected List<Page> pages;
|
protected List<Page> pages;
|
||||||
|
protected List<Chapter> chapters;
|
||||||
protected Class<? extends ImageRegionDecoder> regionDecoderClass;
|
protected Class<? extends ImageRegionDecoder> regionDecoderClass;
|
||||||
protected Class<? extends ImageDecoder> bitmapDecoderClass;
|
protected Class<? extends ImageDecoder> bitmapDecoderClass;
|
||||||
|
|
||||||
|
private boolean hasRequestedNextChapter;
|
||||||
|
|
||||||
public static final int RAPID_DECODER = 0;
|
public static final int RAPID_DECODER = 0;
|
||||||
public static final int SKIA_DECODER = 1;
|
public static final int SKIA_DECODER = 1;
|
||||||
|
|
||||||
public void updatePageNumber() {
|
public void updatePageNumber() {
|
||||||
getReaderActivity().onPageChanged(getCurrentPage(), getTotalPages());
|
getReaderActivity().onPageChanged(getCurrentPage().getPageNumber(), getCurrentPage().getChapter().getPages().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentPage() {
|
public Page getCurrentPage() {
|
||||||
return currentPage;
|
return pages.get(currentPage);
|
||||||
}
|
|
||||||
|
|
||||||
public int getPageForPosition(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPositionForPage(int page) {
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPageChanged(int position) {
|
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();
|
updatePageNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTotalPages() {
|
private void onChapterChanged(Chapter chapter, Page currentPage) {
|
||||||
return pages == null ? 0 : pages.size();
|
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 setSelectedPage(int pageNumber);
|
||||||
public abstract void onPageListReady(List<Page> pages, int currentPage);
|
public abstract void onSetChapter(Chapter chapter, Page currentPage);
|
||||||
public abstract boolean onImageTouch(MotionEvent motionEvent);
|
public abstract void onAppendChapter(Chapter chapter);
|
||||||
|
|
||||||
public void setDecoderClass(int value) {
|
public void setDecoderClass(int value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.base;
|
|
||||||
|
|
||||||
public interface OnChapterSingleTapListener {
|
|
||||||
void onCenterTap();
|
|
||||||
void onLeftSideTap();
|
|
||||||
void onRightSideTap();
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.base;
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager;
|
||||||
|
|
||||||
public interface OnChapterBoundariesOutListener {
|
public interface OnChapterBoundariesOutListener {
|
||||||
void onFirstPageOutEvent();
|
void onFirstPageOutEvent();
|
|
@ -1,11 +1,8 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager;
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager;
|
||||||
|
|
||||||
import android.support.v4.view.PagerAdapter;
|
import android.support.v4.view.PagerAdapter;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.ViewGroup;
|
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;
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public interface Pager {
|
public interface Pager {
|
||||||
|
@ -24,13 +21,7 @@ public interface Pager {
|
||||||
PagerAdapter getAdapter();
|
PagerAdapter getAdapter();
|
||||||
void setAdapter(PagerAdapter adapter);
|
void setAdapter(PagerAdapter adapter);
|
||||||
|
|
||||||
boolean onImageTouch(MotionEvent motionEvent);
|
|
||||||
|
|
||||||
void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener);
|
void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener);
|
||||||
void setOnChapterSingleTapListener(OnChapterSingleTapListener listener);
|
|
||||||
|
|
||||||
OnChapterBoundariesOutListener getChapterBoundariesListener();
|
|
||||||
OnChapterSingleTapListener getChapterSingleTapListener();
|
|
||||||
|
|
||||||
void setOnPageChangeListener(Action1<Integer> onPageChanged);
|
void setOnPageChangeListener(Action1<Integer> onPageChanged);
|
||||||
void clearOnPageChangeListeners();
|
void clearOnPageChangeListeners();
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,16 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager;
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager;
|
||||||
|
|
||||||
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.R;
|
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.preference.PreferencesHelper;
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page;
|
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.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.LeftToRightReader;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader;
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader;
|
||||||
import rx.subscriptions.CompositeSubscription;
|
import rx.subscriptions.CompositeSubscription;
|
||||||
|
@ -21,8 +21,8 @@ public abstract class PagerReader extends BaseReader {
|
||||||
|
|
||||||
protected PagerReaderAdapter adapter;
|
protected PagerReaderAdapter adapter;
|
||||||
protected Pager pager;
|
protected Pager pager;
|
||||||
|
protected GestureDetector gestureDetector;
|
||||||
|
|
||||||
private boolean isReady;
|
|
||||||
protected boolean transitions;
|
protected boolean transitions;
|
||||||
protected CompositeSubscription subscriptions;
|
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_RIGHT = 3;
|
||||||
public static final int ALIGN_CENTER = 4;
|
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) {
|
protected void initializePager(Pager pager) {
|
||||||
this.pager = pager;
|
this.pager = pager;
|
||||||
pager.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
pager.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||||
|
@ -42,30 +45,15 @@ public abstract class PagerReader extends BaseReader {
|
||||||
pager.setOnChapterBoundariesOutListener(new OnChapterBoundariesOutListener() {
|
pager.setOnChapterBoundariesOutListener(new OnChapterBoundariesOutListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFirstPageOutEvent() {
|
public void onFirstPageOutEvent() {
|
||||||
onFirstPageOut();
|
getReaderActivity().requestPreviousChapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLastPageOutEvent() {
|
public void onLastPageOutEvent() {
|
||||||
onLastPageOut();
|
getReaderActivity().requestNextChapter();
|
||||||
}
|
|
||||||
});
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gestureDetector = createGestureDetector();
|
||||||
|
|
||||||
adapter = new PagerReaderAdapter(getChildFragmentManager());
|
adapter = new PagerReaderAdapter(getChildFragmentManager());
|
||||||
pager.setAdapter(adapter);
|
pager.setAdapter(adapter);
|
||||||
|
@ -77,28 +65,27 @@ public abstract class PagerReader extends BaseReader {
|
||||||
.doOnNext(this::setDecoderClass)
|
.doOnNext(this::setDecoderClass)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe(v -> adapter.notifyDataSetChanged()));
|
.subscribe(v -> pager.setAdapter(adapter)));
|
||||||
|
|
||||||
subscriptions.add(preferences.imageScaleType()
|
subscriptions.add(preferences.imageScaleType()
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.doOnNext(this::setImageScaleType)
|
.doOnNext(this::setImageScaleType)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe(v -> adapter.notifyDataSetChanged()));
|
.subscribe(v -> pager.setAdapter(adapter)));
|
||||||
|
|
||||||
subscriptions.add(preferences.zoomStart()
|
subscriptions.add(preferences.zoomStart()
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.doOnNext(this::setZoomStart)
|
.doOnNext(this::setZoomStart)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe(v -> adapter.notifyDataSetChanged()));
|
.subscribe(v -> pager.setAdapter(adapter)));
|
||||||
|
|
||||||
subscriptions.add(preferences.enableTransitions()
|
subscriptions.add(preferences.enableTransitions()
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.subscribe(value -> transitions = value));
|
.subscribe(value -> transitions = value));
|
||||||
|
|
||||||
setPages();
|
setPages();
|
||||||
isReady = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,14 +94,41 @@ public abstract class PagerReader extends BaseReader {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected GestureDetector createGestureDetector() {
|
||||||
public void onPageListReady(List<Page> pages, int currentPage) {
|
return new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||||
if (this.pages != pages) {
|
@Override
|
||||||
this.pages = pages;
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||||
this.currentPage = currentPage;
|
final float positionX = e.getX();
|
||||||
if (isReady) {
|
|
||||||
setPages();
|
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
|
@Override
|
||||||
public void setSelectedPage(int pageNumber) {
|
public void setSelectedPage(int pageNumber) {
|
||||||
pager.setCurrentItem(getPositionForPage(pageNumber), false);
|
pager.setCurrentItem(pageNumber, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void onLeftSideTap() {
|
||||||
public boolean onImageTouch(MotionEvent motionEvent) {
|
if (pager.getCurrentItem() != 0) {
|
||||||
return pager.onImageTouch(motionEvent);
|
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) {
|
private void setImageScaleType(int scaleType) {
|
||||||
|
@ -155,7 +180,4 @@ public abstract class PagerReader extends BaseReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void onFirstPageOut();
|
|
||||||
public abstract void onLastPageOut();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,10 @@ public class PagerReaderAdapter extends FragmentStatePagerAdapter {
|
||||||
public Object instantiateItem(ViewGroup container, int position) {
|
public Object instantiateItem(ViewGroup container, int position) {
|
||||||
PagerReaderFragment f = (PagerReaderFragment) super.instantiateItem(container, position);
|
PagerReaderFragment f = (PagerReaderFragment) super.instantiateItem(container, position);
|
||||||
f.setPage(pages.get(position));
|
f.setPage(pages.get(position));
|
||||||
|
f.setPosition(position);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemPosition(Object object) {
|
|
||||||
return POSITION_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Page> getPages() {
|
public List<Page> getPages() {
|
||||||
return pages;
|
return pages;
|
||||||
}
|
}
|
||||||
|
@ -48,4 +44,17 @@ public class PagerReaderAdapter extends FragmentStatePagerAdapter {
|
||||||
notifyDataSetChanged();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import eu.kanade.tachiyomi.R;
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page;
|
import eu.kanade.tachiyomi.data.source.model.Page;
|
||||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment;
|
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment;
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
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 eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
|
@ -42,9 +43,12 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
@Bind(R.id.retry_button) Button retryButton;
|
@Bind(R.id.retry_button) Button retryButton;
|
||||||
|
|
||||||
private Page page;
|
private Page page;
|
||||||
private boolean isReady;
|
|
||||||
private Subscription progressSubscription;
|
private Subscription progressSubscription;
|
||||||
private Subscription statusSubscription;
|
private Subscription statusSubscription;
|
||||||
|
private int position = -1;
|
||||||
|
|
||||||
|
private int lightGreyColor;
|
||||||
|
private int blackColor;
|
||||||
|
|
||||||
public static PagerReaderFragment newInstance() {
|
public static PagerReaderFragment newInstance() {
|
||||||
return new PagerReaderFragment();
|
return new PagerReaderFragment();
|
||||||
|
@ -57,8 +61,15 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
ReaderActivity activity = getReaderActivity();
|
ReaderActivity activity = getReaderActivity();
|
||||||
PagerReader parentFragment = (PagerReader) getParentFragment();
|
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) {
|
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);
|
imageView.setParallelLoadingEnabled(true);
|
||||||
|
@ -69,7 +80,7 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
imageView.setRegionDecoderClass(parentFragment.getRegionDecoderClass());
|
imageView.setRegionDecoderClass(parentFragment.getRegionDecoderClass());
|
||||||
imageView.setBitmapDecoderClass(parentFragment.getBitmapDecoderClass());
|
imageView.setBitmapDecoderClass(parentFragment.getBitmapDecoderClass());
|
||||||
imageView.setVerticalScrollingParent(parentFragment instanceof VerticalReader);
|
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() {
|
imageView.setOnImageEventListener(new SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onReady() {
|
public void onReady() {
|
||||||
|
@ -103,7 +114,6 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
observeStatus();
|
observeStatus();
|
||||||
isReady = true;
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +121,7 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
unsubscribeProgress();
|
unsubscribeProgress();
|
||||||
unsubscribeStatus();
|
unsubscribeStatus();
|
||||||
|
imageView.setOnTouchListener(null);
|
||||||
imageView.setOnImageEventListener(null);
|
imageView.setOnImageEventListener(null);
|
||||||
ButterKnife.unbind(this);
|
ButterKnife.unbind(this);
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
@ -118,11 +129,17 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
|
|
||||||
public void setPage(Page page) {
|
public void setPage(Page page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
if (isReady) {
|
|
||||||
|
// This method can be called before the view is created
|
||||||
|
if (imageView != null) {
|
||||||
observeStatus();
|
observeStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPosition(int position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
private void showImage() {
|
private void showImage() {
|
||||||
if (page == null || page.getImagePath() == null)
|
if (page == null || page.getImagePath() == null)
|
||||||
return;
|
return;
|
||||||
|
@ -160,8 +177,7 @@ public class PagerReaderFragment extends BaseFragment {
|
||||||
errorText.setGravity(Gravity.CENTER);
|
errorText.setGravity(Gravity.CENTER);
|
||||||
errorText.setText(R.string.decode_image_error);
|
errorText.setText(R.string.decode_image_error);
|
||||||
errorText.setTextColor(getReaderActivity().getReaderTheme() == ReaderActivity.BLACK_THEME ?
|
errorText.setTextColor(getReaderActivity().getReaderTheme() == ReaderActivity.BLACK_THEME ?
|
||||||
ContextCompat.getColor(getContext(), R.color.light_grey) :
|
lightGreyColor : blackColor);
|
||||||
ContextCompat.getColor(getContext(), R.color.primary_text));
|
|
||||||
|
|
||||||
view.addView(errorText);
|
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() {
|
private ReaderActivity getReaderActivity() {
|
||||||
return (ReaderActivity) getActivity();
|
return (ReaderActivity) getActivity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,38 +2,21 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener;
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.OnChapterBoundariesOutListener;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener;
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager;
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener;
|
|
||||||
import rx.functions.Action1;
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public class HorizontalPager extends ViewPager implements Pager {
|
public class HorizontalPager extends ViewPager implements Pager {
|
||||||
|
|
||||||
private GestureDetector gestureDetector;
|
|
||||||
|
|
||||||
private OnChapterBoundariesOutListener onChapterBoundariesOutListener;
|
private OnChapterBoundariesOutListener onChapterBoundariesOutListener;
|
||||||
private OnChapterSingleTapListener onChapterSingleTapListener;
|
|
||||||
|
|
||||||
private static final float SWIPE_TOLERANCE = 0.25f;
|
private static final float SWIPE_TOLERANCE = 0.25f;
|
||||||
private float startDragX;
|
private float startDragX;
|
||||||
|
|
||||||
public HorizontalPager(Context context) {
|
public HorizontalPager(Context context) {
|
||||||
super(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
|
@Override
|
||||||
|
@ -86,31 +69,11 @@ public class HorizontalPager extends ViewPager implements Pager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onImageTouch(MotionEvent event) {
|
|
||||||
return gestureDetector.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) {
|
public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) {
|
||||||
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
|
@Override
|
||||||
public void setOnPageChangeListener(Action1<Integer> function) {
|
public void setOnPageChangeListener(Action1<Integer> function) {
|
||||||
addOnPageChangeListener(new SimpleOnPageChangeListener() {
|
addOnPageChangeListener(new SimpleOnPageChangeListener() {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +1,19 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal;
|
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
|
@Override
|
||||||
public void onFirstPageOut() {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
|
||||||
getReaderActivity().requestPreviousChapter();
|
HorizontalPager pager = new HorizontalPager(getActivity());
|
||||||
}
|
initializePager(pager);
|
||||||
|
return pager;
|
||||||
@Override
|
|
||||||
public void onLastPageOut() {
|
|
||||||
getReaderActivity().requestNextChapter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,30 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal;
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import android.os.Bundle;
|
||||||
import java.util.Collections;
|
import android.view.LayoutInflater;
|
||||||
import java.util.List;
|
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
|
@Override
|
||||||
public void onPageListReady(List<Page> pages, int currentPage) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
|
||||||
ArrayList<Page> inversedPages = new ArrayList<>(pages);
|
HorizontalPager pager = new HorizontalPager(getActivity());
|
||||||
Collections.reverse(inversedPages);
|
pager.setRotation(180);
|
||||||
super.onPageListReady(inversedPages, currentPage);
|
initializePager(pager);
|
||||||
|
return pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPageForPosition(int position) {
|
protected void onLeftSideTap() {
|
||||||
return (getTotalPages() - 1) - position;
|
super.onRightSideTap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPositionForPage(int page) {
|
protected void onRightSideTap() {
|
||||||
return (getTotalPages() - 1) - page;
|
super.onLeftSideTap();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFirstPageOut() {
|
|
||||||
getReaderActivity().requestNextChapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLastPageOut() {
|
|
||||||
getReaderActivity().requestPreviousChapter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,21 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical;
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener;
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.OnChapterBoundariesOutListener;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener;
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager;
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener;
|
|
||||||
import rx.functions.Action1;
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public class VerticalPager extends VerticalViewPagerImpl implements Pager {
|
public class VerticalPager extends VerticalViewPagerImpl implements Pager {
|
||||||
|
|
||||||
private GestureDetector gestureDetector;
|
|
||||||
|
|
||||||
private OnChapterBoundariesOutListener onChapterBoundariesOutListener;
|
private OnChapterBoundariesOutListener onChapterBoundariesOutListener;
|
||||||
private OnChapterSingleTapListener onChapterSingleTapListener;
|
|
||||||
|
|
||||||
private static final float SWIPE_TOLERANCE = 0.25f;
|
private static final float SWIPE_TOLERANCE = 0.25f;
|
||||||
private float startDragY;
|
private float startDragY;
|
||||||
|
|
||||||
public VerticalPager(Context context) {
|
public VerticalPager(Context context) {
|
||||||
super(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
|
@Override
|
||||||
|
@ -85,31 +68,11 @@ public class VerticalPager extends VerticalViewPagerImpl implements Pager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onImageTouch(MotionEvent event) {
|
|
||||||
return gestureDetector.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) {
|
public void setOnChapterBoundariesOutListener(OnChapterBoundariesOutListener listener) {
|
||||||
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
|
@Override
|
||||||
public void setOnPageChangeListener(Action1<Integer> function) {
|
public void setOnPageChangeListener(Action1<Integer> function) {
|
||||||
addOnPageChangeListener(new SimpleOnPageChangeListener() {
|
addOnPageChangeListener(new SimpleOnPageChangeListener() {
|
||||||
|
|
|
@ -16,14 +16,4 @@ public class VerticalReader extends PagerReader {
|
||||||
return pager;
|
return pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFirstPageOut() {
|
|
||||||
getReaderActivity().requestPreviousChapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLastPageOut() {
|
|
||||||
getReaderActivity().requestNextChapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class WebtoonAdapter extends RecyclerView.Adapter<WebtoonHolder> {
|
||||||
public WebtoonAdapter(WebtoonReader fragment) {
|
public WebtoonAdapter(WebtoonReader fragment) {
|
||||||
this.fragment = fragment;
|
this.fragment = fragment;
|
||||||
pages = new ArrayList<>();
|
pages = new ArrayList<>();
|
||||||
touchListener = (v, event) -> fragment.onImageTouch(event);
|
touchListener = (v, event) -> fragment.gestureDetector.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page getItem(int position) {
|
public Page getItem(int position) {
|
||||||
|
|
|
@ -8,8 +8,9 @@ import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
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.data.source.model.Page;
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader;
|
import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader;
|
||||||
import eu.kanade.tachiyomi.widget.PreCachingLayoutManager;
|
import eu.kanade.tachiyomi.widget.PreCachingLayoutManager;
|
||||||
|
@ -27,12 +28,11 @@ public class WebtoonReader extends BaseReader {
|
||||||
private PreCachingLayoutManager layoutManager;
|
private PreCachingLayoutManager layoutManager;
|
||||||
private Subscription subscription;
|
private Subscription subscription;
|
||||||
private Subscription decoderSubscription;
|
private Subscription decoderSubscription;
|
||||||
private GestureDetector gestureDetector;
|
protected GestureDetector gestureDetector;
|
||||||
|
|
||||||
private boolean isReady;
|
|
||||||
private int scrollDistance;
|
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 LEFT_REGION = 0.33f;
|
||||||
private static final float RIGHT_REGION = 0.66f;
|
private static final float RIGHT_REGION = 0.66f;
|
||||||
|
@ -47,7 +47,7 @@ public class WebtoonReader extends BaseReader {
|
||||||
layoutManager = new PreCachingLayoutManager(getActivity());
|
layoutManager = new PreCachingLayoutManager(getActivity());
|
||||||
layoutManager.setExtraLayoutSpace(screenHeight / 2);
|
layoutManager.setExtraLayoutSpace(screenHeight / 2);
|
||||||
if (savedState != null) {
|
if (savedState != null) {
|
||||||
layoutManager.onRestoreInstanceState(savedState.getParcelable(SCROLL_STATE));
|
layoutManager.scrollToPositionWithOffset(savedState.getInt(SAVED_POSITION), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
recycler = new RecyclerView(getActivity());
|
recycler = new RecyclerView(getActivity());
|
||||||
|
@ -80,8 +80,6 @@ public class WebtoonReader extends BaseReader {
|
||||||
});
|
});
|
||||||
|
|
||||||
setPages();
|
setPages();
|
||||||
isReady = true;
|
|
||||||
|
|
||||||
return recycler;
|
return recycler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +98,9 @@ public class WebtoonReader extends BaseReader {
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(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() {
|
private void unsubscribeStatus() {
|
||||||
|
@ -110,18 +110,30 @@ public class WebtoonReader extends BaseReader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSelectedPage(int pageNumber) {
|
public void setSelectedPage(int pageNumber) {
|
||||||
recycler.scrollToPosition(getPositionForPage(pageNumber));
|
recycler.scrollToPosition(pageNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageListReady(List<Page> pages, int currentPage) {
|
public void onSetChapter(Chapter chapter, Page currentPage) {
|
||||||
if (this.pages != pages) {
|
pages = new ArrayList<>(chapter.getPages());
|
||||||
this.pages = pages;
|
// Restoring current page is not supported. It's getting weird scrolling jumps
|
||||||
// Restoring current page is not supported. It's getting weird scrolling jumps
|
// this.currentPage = currentPage;
|
||||||
// this.currentPage = currentPage;
|
|
||||||
if (isReady) {
|
// This method can be called before the view is created
|
||||||
setPages();
|
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() {
|
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
super.onScrolled(recyclerView, dx, dy);
|
int page = layoutManager.findLastVisibleItemPosition();
|
||||||
|
if (page != currentPage) {
|
||||||
currentPage = layoutManager.findLastVisibleItemPosition();
|
onPageChanged(page);
|
||||||
updatePageNumber();
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onImageTouch(MotionEvent motionEvent) {
|
|
||||||
return gestureDetector.onTouchEvent(motionEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void observeStatus(int position) {
|
private void observeStatus(int position) {
|
||||||
if (position == pages.size())
|
if (position == pages.size())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<string name="pref_custom_brightness_value_key">pref_custom_brightness_value_key</string>
|
<string name="pref_custom_brightness_value_key">pref_custom_brightness_value_key</string>
|
||||||
<string name="pref_reader_theme_key">pref_reader_theme_key</string>
|
<string name="pref_reader_theme_key">pref_reader_theme_key</string>
|
||||||
<string name="pref_image_decoder_key">pref_image_decoder_key</string>
|
<string name="pref_image_decoder_key">pref_image_decoder_key</string>
|
||||||
|
<string name="pref_seamless_mode_key">pref_seamless_mode_key</string>
|
||||||
|
|
||||||
<string name="pref_download_directory_key">pref_download_directory_key</string>
|
<string name="pref_download_directory_key">pref_download_directory_key</string>
|
||||||
<string name="pref_download_slots_key">pref_download_slots_key</string>
|
<string name="pref_download_slots_key">pref_download_slots_key</string>
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
<string name="pref_enable_transitions">Enable transitions</string>
|
<string name="pref_enable_transitions">Enable transitions</string>
|
||||||
<string name="pref_show_page_number">Show page number</string>
|
<string name="pref_show_page_number">Show page number</string>
|
||||||
<string name="pref_custom_brightness">Use custom brightness</string>
|
<string name="pref_custom_brightness">Use custom brightness</string>
|
||||||
|
<string name="pref_seamless_mode">Enable seamless chapter transitions</string>
|
||||||
<string name="pref_keep_screen_on">Keep screen on</string>
|
<string name="pref_keep_screen_on">Keep screen on</string>
|
||||||
<string name="pref_reader_theme">Background color</string>
|
<string name="pref_reader_theme">Background color</string>
|
||||||
<string name="white_theme">White</string>
|
<string name="white_theme">White</string>
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
android:key="@string/pref_custom_brightness_key"
|
android:key="@string/pref_custom_brightness_key"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreference android:title="@string/pref_seamless_mode"
|
||||||
|
android:key="@string/pref_seamless_mode_key"
|
||||||
|
android:defaultValue="true" />
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
||||||
android:title="@string/pref_viewer_type"
|
android:title="@string/pref_viewer_type"
|
||||||
android:key="@string/pref_default_viewer_key"
|
android:key="@string/pref_default_viewer_key"
|
||||||
|
|
Loading…
Reference in a new issue