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 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<Page> pages;
|
||||
|
||||
public Chapter() {}
|
||||
|
||||
public void setUrl(String url) {
|
||||
|
@ -68,4 +73,15 @@ public class Chapter implements Serializable {
|
|||
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);
|
||||
}
|
||||
|
||||
public boolean seamlessMode() {
|
||||
return prefs.getBoolean(getKey(R.string.pref_seamless_mode_key), true);
|
||||
}
|
||||
|
||||
public Preference<Boolean> catalogueAsList() {
|
||||
return rxPrefs.getBoolean(getKey(R.string.pref_display_catalogue_as_list), false);
|
||||
}
|
||||
|
|
|
@ -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<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);
|
||||
}
|
||||
|
||||
public void onChapterReady(List<Page> 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<Page> 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<ReaderPresenter> {
|
|||
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<ReaderPresenter> {
|
|||
}
|
||||
|
||||
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<ReaderPresenter> {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ReaderActivity> {
|
|||
@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<Page> pageList;
|
||||
private List<Page> nextChapterPageList;
|
||||
private List<MangaSync> mangaSyncList;
|
||||
|
||||
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_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<ReaderActivity> {
|
|||
|
||||
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<ReaderActivity> {
|
|||
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<List<Page>> getPageListObservable() {
|
||||
return isDownloaded ?
|
||||
private Observable<Chapter> 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<Page> getPageImagesObservable() {
|
||||
Observable<Page> 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<Pair<Chapter, Chapter>> 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<ReaderActivity> {
|
|||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
// Listen for retry page events
|
||||
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
|
||||
// Preload the first pages of the next chapter. Only for non seamless mode
|
||||
private Observable<Page> 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<ReaderActivity> {
|
|||
|
||||
private Observable<List<MangaSync>> getMangaSyncObservable() {
|
||||
return db.getMangasSync(manga).asRxObservable()
|
||||
.take(1)
|
||||
.doOnNext(mangaSync -> this.mangaSyncList = mangaSync);
|
||||
}
|
||||
|
||||
|
@ -207,24 +226,58 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
|||
|
||||
// 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<ReaderActivity> {
|
|||
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<ReaderActivity> {
|
|||
}
|
||||
}
|
||||
|
||||
public void setCurrentPage(int currentPage) {
|
||||
public void setCurrentPage(Page currentPage) {
|
||||
this.currentPage = currentPage;
|
||||
}
|
||||
|
||||
|
@ -334,8 +388,8 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
|||
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<ReaderActivity> {
|
|||
return manga;
|
||||
}
|
||||
|
||||
public Page getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
public boolean isSeamlessMode() {
|
||||
return seamlessMode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Page> pages;
|
||||
protected List<Chapter> chapters;
|
||||
protected Class<? extends ImageRegionDecoder> regionDecoderClass;
|
||||
protected Class<? extends ImageDecoder> 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<Page> 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) {
|
||||
|
|
|
@ -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 {
|
||||
void onFirstPageOutEvent();
|
|
@ -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<Integer> onPageChanged);
|
||||
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;
|
||||
|
||||
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<Page> 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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Page> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<Integer> function) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Page> pages, int currentPage) {
|
||||
ArrayList<Page> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Integer> function) {
|
||||
addOnPageChangeListener(new SimpleOnPageChangeListener() {
|
||||
|
|
|
@ -16,14 +16,4 @@ public class VerticalReader extends PagerReader {
|
|||
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) {
|
||||
this.fragment = fragment;
|
||||
pages = new ArrayList<>();
|
||||
touchListener = (v, event) -> fragment.onImageTouch(event);
|
||||
touchListener = (v, event) -> fragment.gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
public Page getItem(int position) {
|
||||
|
|
|
@ -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<Page> 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;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<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_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_slots_key">pref_download_slots_key</string>
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
<string name="pref_enable_transitions">Enable transitions</string>
|
||||
<string name="pref_show_page_number">Show page number</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_reader_theme">Background color</string>
|
||||
<string name="white_theme">White</string>
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
android:key="@string/pref_custom_brightness_key"
|
||||
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
|
||||
android:title="@string/pref_viewer_type"
|
||||
android:key="@string/pref_default_viewer_key"
|
||||
|
|
Reference in a new issue