package com.jparkie.aizoban.presenters; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import com.bumptech.glide.Glide; import com.jparkie.aizoban.BuildConfig; import com.jparkie.aizoban.controllers.QueryManager; import com.jparkie.aizoban.controllers.events.SelectPageEvent; import com.jparkie.aizoban.controllers.factories.DefaultFactory; import com.jparkie.aizoban.models.Chapter; import com.jparkie.aizoban.models.databases.RecentChapter; import com.jparkie.aizoban.models.downloads.DownloadChapter; import com.jparkie.aizoban.presenters.mapper.ChapterMapper; import com.jparkie.aizoban.utils.PreferenceUtils; import com.jparkie.aizoban.utils.wrappers.DownloadChapterSortCursorWrapper; import com.jparkie.aizoban.utils.wrappers.RequestWrapper; import com.jparkie.aizoban.views.ChapterView; import com.jparkie.aizoban.views.activities.ChapterActivity; import com.jparkie.aizoban.views.activities.MangaActivity; import com.jparkie.aizoban.views.adapters.PagesAdapter; import com.jparkie.aizoban.views.fragments.ChapterHelpFragment; import com.jparkie.aizoban.views.fragments.SelectPageFragment; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import de.greenrobot.event.EventBus; import rx.Observable; import rx.Observer; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Func1; import rx.functions.Func2; import rx.schedulers.Schedulers; public class ChapterPresenterOfflineImpl implements ChapterPresenter { public static final String TAG = ChapterPresenterOfflineImpl.class.getSimpleName(); private static final String REQUEST_PARCELABLE_KEY = TAG + ":" + "RequestParcelableKey"; private static final String IMAGE_URLS_PARCELABLE_KEY = TAG + ":" + "ImageUrlsParcelableKey"; private static final String INITIALIZED_PARCELABLE_KEY = TAG + ":" + "InitializedParcelableKey"; private static final String POSITION_PARCELABLE_KEY = TAG + ":" + "PositionParcelableKey"; private ChapterView mChapterView; private ChapterMapper mChapterMapper; private PagesAdapter mPagesAdapter; private RequestWrapper mRequest; private DownloadChapter mDownloadChapter; private RecentChapter mRecentChapter; private ArrayList<String> mImageUrls; private boolean mIsRightToLeftDirection; private boolean mIsLockOrientation; private boolean mIsLockZoom; private boolean mInitialized; private int mInitialPosition; private Subscription mQueryDownloadChapterSubscription; private Subscription mQueryRecentChapterSubscription; public ChapterPresenterOfflineImpl(ChapterView chapterView, ChapterMapper chapterMapper) { mChapterView = chapterView; mChapterMapper = chapterMapper; } @Override public void handleInitialArguments(Intent arguments) { if (arguments != null) { if (arguments.hasExtra(ChapterActivity.REQUEST_ARGUMENT_KEY)) { mRequest = arguments.getParcelableExtra(ChapterActivity.REQUEST_ARGUMENT_KEY); arguments.removeExtra(ChapterActivity.REQUEST_ARGUMENT_KEY); } if (arguments.hasExtra(ChapterActivity.POSITION_ARGUMENT_KEY)) { mInitialPosition = arguments.getIntExtra(ChapterActivity.POSITION_ARGUMENT_KEY, 0); arguments.removeExtra(ChapterActivity.POSITION_ARGUMENT_KEY); } } } @Override public void initializeViews() { mChapterView.initializeHardwareAcceleration(); mChapterView.initializeSystemUIVisibility(); mChapterView.initializeToolbar(); mChapterView.initializeViewPager(); mChapterView.initializeEmptyRelativeLayout(); mChapterView.initializeButtons(); mChapterView.initializeTextView(); } @Override public void initializeOptions() { mIsRightToLeftDirection = PreferenceUtils.isRightToLeftDirection(); mIsLockOrientation = PreferenceUtils.isLockOrientation(); mIsLockZoom = PreferenceUtils.isLockZoom(); mChapterMapper.applyIsLockOrientation(mIsLockOrientation); mChapterMapper.applyIsLockZoom(mIsLockZoom); } @Override public void initializeMenu() { mChapterView.setOptionDirectionText(mIsRightToLeftDirection); mChapterView.setOptionOrientationText(mIsLockOrientation); mChapterView.setOptionZoomText(mIsLockZoom); } @Override public void initializeDataFromUrl(FragmentManager fragmentManager) { mPagesAdapter = new PagesAdapter(fragmentManager); mPagesAdapter.setIsRightToLeftDirection(mIsRightToLeftDirection); mChapterMapper.registerAdapter(mPagesAdapter); initializeRecentChapter(); if (!mInitialized) { queryChapterFromUrl(); } else { if (mDownloadChapter != null) { mChapterView.setTitleText(mDownloadChapter.getName()); } if (mImageUrls != null && mImageUrls.size() != 0) { updateAdapter(); mChapterView.hideEmptyRelativeLayout(); } } } @Override public void registerForEvents() { EventBus.getDefault().register(this); } public void onEventMainThread(SelectPageEvent event) { if (event != null) { setPosition(event.getSelectPage()); } } @Override public void unregisterForEvents() { EventBus.getDefault().unregister(this); } @Override public void saveState(Bundle outState) { if (mRequest != null) { outState.putParcelable(REQUEST_PARCELABLE_KEY, mRequest); } if (mDownloadChapter != null) { outState.putParcelable(Chapter.PARCELABLE_KEY, mDownloadChapter); } if (mImageUrls != null) { outState.putStringArrayList(IMAGE_URLS_PARCELABLE_KEY, mImageUrls); } outState.putBoolean(INITIALIZED_PARCELABLE_KEY, mInitialized); outState.putInt(POSITION_PARCELABLE_KEY, mInitialPosition); } @Override public void restoreState(Bundle savedState) { if (savedState.containsKey(REQUEST_PARCELABLE_KEY)) { mRequest = savedState.getParcelable(REQUEST_PARCELABLE_KEY); savedState.remove(REQUEST_PARCELABLE_KEY); } if (savedState.containsKey(Chapter.PARCELABLE_KEY)) { mDownloadChapter = savedState.getParcelable(Chapter.PARCELABLE_KEY); savedState.remove(Chapter.PARCELABLE_KEY); } if (savedState.containsKey(IMAGE_URLS_PARCELABLE_KEY)) { mImageUrls = savedState.getStringArrayList(IMAGE_URLS_PARCELABLE_KEY); savedState.remove(IMAGE_URLS_PARCELABLE_KEY); } if (savedState.containsKey(INITIALIZED_PARCELABLE_KEY)) { mInitialized = savedState.getBoolean(INITIALIZED_PARCELABLE_KEY, false); savedState.remove(INITIALIZED_PARCELABLE_KEY); } if (savedState.containsKey(POSITION_PARCELABLE_KEY)) { mInitialPosition = savedState.getInt(POSITION_PARCELABLE_KEY, 0); savedState.remove(POSITION_PARCELABLE_KEY); } } @Override public void saveChapterToRecentChapters() { try { if (mInitialized) { if (mRecentChapter == null) { mRecentChapter = DefaultFactory.RecentChapter.constructDefault(); mRecentChapter.setSource(mDownloadChapter.getSource()); mRecentChapter.setUrl(mDownloadChapter.getUrl()); mRecentChapter.setParentUrl(mDownloadChapter.getParentUrl()); mRecentChapter.setName(mDownloadChapter.getName()); mRecentChapter.setOffline(true); } mRecentChapter.setThumbnailUrl(mImageUrls.get(getActualPosition())); mRecentChapter.setDate(System.currentTimeMillis()); mRecentChapter.setPageNumber(getActualPosition()); QueryManager.putObjectToApplicationDatabase(mRecentChapter); } } catch (Throwable e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } } @Override public void destroyAllSubscriptions() { if (mQueryDownloadChapterSubscription != null) { mQueryDownloadChapterSubscription.unsubscribe(); mQueryDownloadChapterSubscription = null; } if (mQueryRecentChapterSubscription != null) { mQueryRecentChapterSubscription.unsubscribe(); mQueryRecentChapterSubscription = null; } } @Override public void onTrimMemory(int level) { Glide.get(mChapterView.getContext()).trimMemory(level); } @Override public void onLowMemory() { Glide.get(mChapterView.getContext()).clearMemory(); } @Override public void onPageSelected(int position) { mChapterView.setSubtitlePositionText(getActualPosition() + 1); mChapterView.setImmersivePositionText(getActualPosition() + 1); mChapterMapper.applyViewSettings(); } @Override public void onFirstPageOut() { if (mDownloadChapter != null) { if (mIsRightToLeftDirection) { nextChapter(); } else { previousChapter(); } } } @Override public void onLastPageOut() { if (mDownloadChapter != null) { if (mIsRightToLeftDirection) { previousChapter(); } else { nextChapter(); } } } @Override public void onPreviousClick() { previousChapter(); } @Override public void onNextClick() { nextChapter(); } @Override public void onOptionParent() { if (mDownloadChapter != null) { Intent mangaIntent = MangaActivity.constructOfflineMangaActivityIntent(mChapterView.getContext(), new RequestWrapper(mDownloadChapter.getSource(), mDownloadChapter.getParentUrl())); mangaIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mChapterView.finishAndLaunchActivity(mangaIntent, false); } else { mChapterView.toastNotInitializedError(); } } @Override public void onOptionRefresh() { if (mInitialized) { mPagesAdapter.notifyDataSetChanged(); } } @Override public void onOptionSelectPage() { if (mInitialized) { if (mImageUrls != null) { if (((FragmentActivity) mChapterView.getContext()).getSupportFragmentManager().findFragmentByTag(SelectPageFragment.TAG) == null) { SelectPageFragment selectPageFragment = SelectPageFragment.newInstance(getActualPosition(), mImageUrls.size()); selectPageFragment.show(((FragmentActivity) mChapterView.getContext()).getSupportFragmentManager(), SelectPageFragment.TAG); } } } } @Override public void onOptionDirection() { if (mInitialized) { mIsRightToLeftDirection = !mIsRightToLeftDirection; updateAdapter(); swapPositions(); mChapterView.setOptionDirectionText(mIsRightToLeftDirection); PreferenceUtils.setDirection(mIsRightToLeftDirection); } else { mChapterView.toastNotInitializedError(); } } @Override public void onOptionOrientation() { if (mInitialized) { mIsLockOrientation = !mIsLockOrientation; mChapterMapper.applyIsLockOrientation(mIsLockOrientation); mChapterView.setOptionOrientationText(mIsLockOrientation); PreferenceUtils.setOrientation(mIsLockOrientation); } else { mChapterView.toastNotInitializedError(); } } @Override public void onOptionZoom() { if (mInitialized) { mIsLockZoom = !mIsLockZoom; mChapterMapper.applyIsLockZoom(mIsLockZoom); mChapterView.setOptionZoomText(mIsLockZoom); PreferenceUtils.setZoom(mIsLockZoom); } else { mChapterView.toastNotInitializedError(); } } @Override public void onOptionHelp() { if (((FragmentActivity)mChapterView.getContext()).getSupportFragmentManager().findFragmentByTag(ChapterHelpFragment.TAG) == null) { ChapterHelpFragment chapterHelpFragment = new ChapterHelpFragment(); chapterHelpFragment.show(((FragmentActivity) mChapterView.getContext()).getSupportFragmentManager(), ChapterHelpFragment.TAG); } } private void initializeRecentChapter() { if (mQueryRecentChapterSubscription != null) { mQueryRecentChapterSubscription.unsubscribe(); mQueryRecentChapterSubscription = null; } if (mRequest != null) { mQueryRecentChapterSubscription = QueryManager .queryRecentChapterFromRequest(mRequest, true) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Cursor>() { @Override public void onCompleted() { // Do Nothing. } @Override public void onError(Throwable e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } @Override public void onNext(Cursor recentCursor) { if (recentCursor != null && recentCursor.getCount() != 0) { mRecentChapter = QueryManager.toObject(recentCursor, RecentChapter.class); } } }); } } private void queryChapterFromUrl() { if (mQueryDownloadChapterSubscription != null) { mQueryDownloadChapterSubscription.unsubscribe(); mQueryDownloadChapterSubscription = null; } if (mRequest != null) { mQueryDownloadChapterSubscription = QueryManager .queryDownloadChapterFromRequest(mRequest) .map(new Func1<Cursor, Cursor>() { @Override public Cursor call(Cursor incomingCursor) { if (incomingCursor != null && incomingCursor.getCount() != 0) { return incomingCursor; } return null; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Cursor>() { @Override public void onCompleted() { if (mDownloadChapter != null) { File chapterDirectory = new File(mDownloadChapter.getDirectory()); if (chapterDirectory.exists() && chapterDirectory.isDirectory()) { initializeImageUrls(chapterDirectory.listFiles()); updateAdapter(); setPosition(mInitialPosition); mChapterView.hideEmptyRelativeLayout(); mChapterView.setTitleText(mDownloadChapter.getName()); mChapterView.setSubtitlePositionText(getActualPosition() + 1); mChapterView.setImmersivePositionText(getActualPosition() + 1); mChapterView.initializeFullscreen(); mInitialized = true; } } } @Override public void onError(Throwable e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } @Override public void onNext(Cursor chapterCursor) { if (chapterCursor != null) { mDownloadChapter = QueryManager.toObject(chapterCursor, DownloadChapter.class); } } }); } } private void initializeImageUrls(File[] files) { mImageUrls = new ArrayList<String>(); File[] imageFiles = files; Arrays.sort(imageFiles, new Comparator<File>() { @Override public int compare(File leftFile, File rightFile) { String leftFileNameAndExtension = leftFile.getName().substring(0, leftFile.getName().indexOf(".")); String rightFileNameAndExtension = rightFile.getName().substring(0, rightFile.getName().indexOf(".")); int leftFileNumber = Integer.parseInt(leftFileNameAndExtension); int rightFileNumber = Integer.parseInt(rightFileNameAndExtension); if (leftFileNumber > rightFileNumber) { return 1; } else if (leftFileNumber == rightFileNumber) { return 0; } else { return -1; } } }); for (File imageFile : imageFiles) { mImageUrls.add(imageFile.getPath()); } } private void updateAdapter() { if (mImageUrls != null) { ArrayList<String> imageUrls = new ArrayList<String>(mImageUrls.size()); if (mIsRightToLeftDirection) { for (String imageUrl : mImageUrls) { imageUrls.add(new String(imageUrl)); } Collections.reverse(imageUrls); } else { imageUrls = mImageUrls; } if (mPagesAdapter != null) { mPagesAdapter.setImageUrls(imageUrls); mPagesAdapter.setIsRightToLeftDirection(mIsRightToLeftDirection); } } } private void setPosition(int position) { if (mPagesAdapter != null && mPagesAdapter.getCount() != 0) { if (position >= 0 && position <= mPagesAdapter.getCount() - 1) { int currentPosition = position; if (mIsRightToLeftDirection) { currentPosition = mPagesAdapter.getCount() - currentPosition - 1; } mChapterMapper.setPosition(currentPosition); } } } private void swapPositions() { if (mPagesAdapter != null && mPagesAdapter.getCount() != 0) { int oldPosition = mChapterMapper.getPosition(); int newPosition = mPagesAdapter.getCount() - oldPosition - 1; mChapterMapper.setPosition(newPosition); } } private int getActualPosition() { int currentPosition = mChapterMapper.getPosition(); if (mPagesAdapter != null && mPagesAdapter.getCount() != 0) { if (mPagesAdapter.getIsRightToLeftDirection()) { currentPosition = mPagesAdapter.getCount() - currentPosition - 1; } } return currentPosition; } private void nextChapter() { if (mDownloadChapter != null) { if (mQueryDownloadChapterSubscription != null) { mQueryDownloadChapterSubscription.unsubscribe(); mQueryDownloadChapterSubscription = null; } Observable<Cursor> queryDownloadChaptersFromUrlObservable = QueryManager .queryDownloadChaptersOfDownloadManga(new RequestWrapper(mDownloadChapter.getSource(), mDownloadChapter.getParentUrl()), true); Observable<List<String>> queryChapterUrlsFromUrlObservable = QueryManager .queryChaptersOfMangaFromRequest(new RequestWrapper(mDownloadChapter.getSource(), mDownloadChapter.getParentUrl()), true) .flatMap(new Func1<Cursor, Observable<Chapter>>() { @Override public Observable<Chapter> call(Cursor chapterCursor) { List<Chapter> chapters = QueryManager.toList(chapterCursor, Chapter.class); return Observable.from(chapters.toArray(new Chapter[chapters.size()])); } }) .flatMap(new Func1<Chapter, Observable<String>>() { @Override public Observable<String> call(Chapter chapter) { return Observable.just(chapter.getUrl()); } }) .toList(); mQueryDownloadChapterSubscription = Observable.zip(queryDownloadChaptersFromUrlObservable, queryChapterUrlsFromUrlObservable, new Func2<Cursor, List<String>, Cursor>() { @Override public Cursor call(Cursor downloadChapterCursor, List<String> sortedChapterUrls) { return new DownloadChapterSortCursorWrapper(downloadChapterCursor, sortedChapterUrls); } }) .flatMap(new Func1<Cursor, Observable<List<DownloadChapter>>>() { @Override public Observable<List<DownloadChapter>> call(Cursor sortedDownloadChapterCursor) { List<DownloadChapter> downloadChapters = QueryManager.toList(sortedDownloadChapterCursor, DownloadChapter.class); return Observable.just(downloadChapters); } }) .map(new Func1<List<DownloadChapter>, String>() { @Override public String call(List<DownloadChapter> downloadChapters) { DownloadChapter currentChapter = null; for (int index = 0; index < downloadChapters.size(); index++) { currentChapter = downloadChapters.get(index); if (currentChapter != null) { if (currentChapter.getUrl().equals(mDownloadChapter.getUrl())) { if (index + 1 < downloadChapters.size()) { return downloadChapters.get(index + 1).getUrl(); } else { break; } } } } return null; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onCompleted() { // Do Nothing. } @Override public void onError(Throwable e) { mChapterView.toastNoNextChapter(); if (BuildConfig.DEBUG) { e.printStackTrace(); } } @Override public void onNext(String adjacentChapterUrl) { if (adjacentChapterUrl != null) { Intent adjacentChapterIntent = ChapterActivity.constructOfflineChapterActivityIntent(mChapterView.getContext(), new RequestWrapper(mDownloadChapter.getSource(), adjacentChapterUrl), 0); mChapterView.finishAndLaunchActivity(adjacentChapterIntent, true); } else { mChapterView.toastNoNextChapter(); } } }); } else { mChapterView.toastNoNextChapter(); } } private void previousChapter() { if (mDownloadChapter != null) { if (mQueryDownloadChapterSubscription != null) { mQueryDownloadChapterSubscription.unsubscribe(); mQueryDownloadChapterSubscription = null; } Observable<Cursor> queryDownloadChaptersFromUrlObservable = QueryManager .queryDownloadChaptersOfDownloadManga(new RequestWrapper(mDownloadChapter.getSource(), mDownloadChapter.getParentUrl()), true); Observable<List<String>> queryChapterUrlsFromUrlObservable = QueryManager .queryChaptersOfMangaFromRequest(new RequestWrapper(mDownloadChapter.getSource(), mDownloadChapter.getParentUrl()), true) .flatMap(new Func1<Cursor, Observable<Chapter>>() { @Override public Observable<Chapter> call(Cursor chapterCursor) { List<Chapter> chapters = QueryManager.toList(chapterCursor, Chapter.class); return Observable.from(chapters.toArray(new Chapter[chapters.size()])); } }) .flatMap(new Func1<Chapter, Observable<String>>() { @Override public Observable<String> call(Chapter chapter) { return Observable.just(chapter.getUrl()); } }) .toList(); mQueryDownloadChapterSubscription = Observable.zip(queryDownloadChaptersFromUrlObservable, queryChapterUrlsFromUrlObservable, new Func2<Cursor, List<String>, Cursor>() { @Override public Cursor call(Cursor downloadChapterCursor, List<String> sortedChapterUrls) { return new DownloadChapterSortCursorWrapper(downloadChapterCursor, sortedChapterUrls); } }) .flatMap(new Func1<Cursor, Observable<List<DownloadChapter>>>() { @Override public Observable<List<DownloadChapter>> call(Cursor sortedDownloadChapterCursor) { List<DownloadChapter> downloadChapters = QueryManager.toList(sortedDownloadChapterCursor, DownloadChapter.class); return Observable.just(downloadChapters); } }) .map(new Func1<List<DownloadChapter>, String>() { @Override public String call(List<DownloadChapter> downloadChapters) { DownloadChapter currentChapter = null; for (int index = 0; index < downloadChapters.size(); index++) { currentChapter = downloadChapters.get(index); if (currentChapter != null) { if (currentChapter.getUrl().equals(mDownloadChapter.getUrl())) { if (index - 1 >= 0) { return downloadChapters.get(index - 1).getUrl(); } else { break; } } } } return null; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onCompleted() { // Do Nothing. } @Override public void onError(Throwable e) { mChapterView.toastNoPreviousChapter(); if (BuildConfig.DEBUG) { e.printStackTrace(); } } @Override public void onNext(String adjacentChapterUrl) { if (adjacentChapterUrl != null) { Intent adjacentChapterIntent = ChapterActivity.constructOfflineChapterActivityIntent(mChapterView.getContext(), new RequestWrapper(mDownloadChapter.getSource(), adjacentChapterUrl), 0); mChapterView.finishAndLaunchActivity(adjacentChapterIntent, true); } else { mChapterView.toastNoPreviousChapter(); } } }); } else { mChapterView.toastNoPreviousChapter(); } } }