Improve info fragment. Other minor changes and fixes.
This commit is contained in:
parent
c52c567eae
commit
eb10d77374
8 changed files with 328 additions and 274 deletions
|
@ -25,7 +25,6 @@ import eu.kanade.mangafeed.data.source.model.Page;
|
||||||
import eu.kanade.mangafeed.event.DownloadChaptersEvent;
|
import eu.kanade.mangafeed.event.DownloadChaptersEvent;
|
||||||
import eu.kanade.mangafeed.util.DiskUtils;
|
import eu.kanade.mangafeed.util.DiskUtils;
|
||||||
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
|
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
|
||||||
import eu.kanade.mangafeed.util.UrlUtil;
|
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
import rx.android.schedulers.AndroidSchedulers;
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
@ -182,8 +181,10 @@ public class DownloadManager {
|
||||||
|
|
||||||
return pageListObservable
|
return pageListObservable
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.doOnNext(pages -> download.setStatus(Download.DOWNLOADING))
|
.doOnNext(pages -> {
|
||||||
.doOnNext(pages -> download.downloadedImages = 0)
|
download.downloadedImages = 0;
|
||||||
|
download.setStatus(Download.DOWNLOADING);
|
||||||
|
})
|
||||||
// Get all the URLs to the source images, fetch pages if necessary
|
// Get all the URLs to the source images, fetch pages if necessary
|
||||||
.flatMap(download.source::getAllImageUrlsFromPageList)
|
.flatMap(download.source::getAllImageUrlsFromPageList)
|
||||||
// Start downloading images, consider we can have downloaded images already
|
// Start downloading images, consider we can have downloaded images already
|
||||||
|
@ -263,10 +264,8 @@ public class DownloadManager {
|
||||||
|
|
||||||
// Get the filename for an image given the page
|
// Get the filename for an image given the page
|
||||||
private String getImageFilename(Page page) {
|
private String getImageFilename(Page page) {
|
||||||
String url = UrlUtil.getPath(page.getImageUrl());
|
String url = page.getImageUrl();
|
||||||
return url.substring(
|
return url.substring(url.lastIndexOf("/") + 1, url.length());
|
||||||
url.lastIndexOf("/") + 1,
|
|
||||||
url.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isImageDownloaded(File imagePath) {
|
private boolean isImageDownloaded(File imagePath) {
|
||||||
|
|
|
@ -39,10 +39,10 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> {
|
||||||
|
|
||||||
public final static String SOURCE_ID = "source_id";
|
public final static String SOURCE_ID = "source_id";
|
||||||
|
|
||||||
public static CatalogueFragment newInstance(int source_id) {
|
public static CatalogueFragment newInstance(int sourceId) {
|
||||||
CatalogueFragment fragment = new CatalogueFragment();
|
CatalogueFragment fragment = new CatalogueFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt(SOURCE_ID, source_id);
|
args.putInt(SOURCE_ID, sourceId);
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,9 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observePagesStatus(Download download, DownloadFragment view) {
|
private void observePagesStatus(Download download, DownloadFragment view) {
|
||||||
|
// Initial update of the downloaded pages
|
||||||
|
view.updateDownloadedPages(download);
|
||||||
|
|
||||||
PublishSubject<Integer> pageStatusSubject = PublishSubject.create();
|
PublishSubject<Integer> pageStatusSubject = PublishSubject.create();
|
||||||
for (Page page : download.pages) {
|
for (Page page : download.pages) {
|
||||||
if (page.getStatus() != Page.READY)
|
if (page.getStatus() != Page.READY)
|
||||||
|
|
|
@ -17,7 +17,6 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
|
||||||
@Inject DatabaseHelper db;
|
@Inject DatabaseHelper db;
|
||||||
|
|
||||||
private long mangaId;
|
private long mangaId;
|
||||||
private Manga manga;
|
|
||||||
|
|
||||||
private static final int DB_MANGA = 1;
|
private static final int DB_MANGA = 1;
|
||||||
|
|
||||||
|
@ -25,19 +24,13 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
|
||||||
protected void onCreate(Bundle savedState) {
|
protected void onCreate(Bundle savedState) {
|
||||||
super.onCreate(savedState);
|
super.onCreate(savedState);
|
||||||
|
|
||||||
restartableLatestCache(DB_MANGA,
|
restartableLatestCache(DB_MANGA, this::getDbMangaObservable, MangaActivity::setManga);
|
||||||
() -> getDbMangaObservable()
|
|
||||||
.doOnNext(manga -> this.manga = manga),
|
|
||||||
(view, manga) -> {
|
|
||||||
view.setManga(manga);
|
|
||||||
EventBus.getDefault().postSticky(manga);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
// Avoid fragments receiving wrong manga
|
// Avoid new instances receiving wrong manga
|
||||||
EventBus.getDefault().removeStickyEvent(Manga.class);
|
EventBus.getDefault().removeStickyEvent(Manga.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +38,8 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
|
||||||
return db.getManga(mangaId).createObservable()
|
return db.getManga(mangaId).createObservable()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.flatMap(Observable::from)
|
.flatMap(Observable::from)
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnNext(manga -> EventBus.getDefault().postSticky(manga));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queryManga(long mangaId) {
|
public void queryManga(long mangaId) {
|
||||||
|
|
|
@ -56,53 +56,39 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
|
||||||
|
|
||||||
restartableLatestCache(DB_CHAPTERS,
|
restartableLatestCache(DB_CHAPTERS,
|
||||||
this::getDbChaptersObs,
|
this::getDbChaptersObs,
|
||||||
ChaptersFragment::onNextChapters
|
ChaptersFragment::onNextChapters);
|
||||||
);
|
|
||||||
|
|
||||||
restartableLatestCache(FETCH_CHAPTERS,
|
restartableFirst(FETCH_CHAPTERS,
|
||||||
this::getOnlineChaptersObs,
|
this::getOnlineChaptersObs,
|
||||||
(view, result) -> view.onFetchChaptersDone(),
|
(view, result) -> view.onFetchChaptersDone(),
|
||||||
(view, error) -> view.onFetchChaptersError()
|
(view, error) -> view.onFetchChaptersError());
|
||||||
);
|
|
||||||
|
|
||||||
restartableLatestCache(CHAPTER_STATUS_CHANGES,
|
restartableLatestCache(CHAPTER_STATUS_CHANGES,
|
||||||
this::getChapterStatusObs,
|
this::getChapterStatusObs,
|
||||||
(view, download) -> view.onChapterStatusChange(download),
|
(view, download) -> view.onChapterStatusChange(download),
|
||||||
(view, error) -> Timber.e(error.getCause(), error.getMessage())
|
(view, error) -> Timber.e(error.getCause(), error.getMessage()));
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onTakeView(ChaptersFragment view) {
|
|
||||||
super.onTakeView(view);
|
|
||||||
registerForStickyEvents();
|
registerForStickyEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDropView() {
|
|
||||||
unregisterForEvents();
|
|
||||||
super.onDropView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
unregisterForEvents();
|
||||||
EventBus.getDefault().removeStickyEvent(ChapterCountEvent.class);
|
EventBus.getDefault().removeStickyEvent(ChapterCountEvent.class);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventBusHook
|
@EventBusHook
|
||||||
public void onEventMainThread(Manga manga) {
|
public void onEventMainThread(Manga manga) {
|
||||||
if (this.manga != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.manga = manga;
|
this.manga = manga;
|
||||||
|
|
||||||
|
if (!isStarted(DB_CHAPTERS)) {
|
||||||
source = sourceManager.get(manga.source);
|
source = sourceManager.get(manga.source);
|
||||||
start(DB_CHAPTERS);
|
start(DB_CHAPTERS);
|
||||||
|
|
||||||
add(db.getChapters(manga).createObservable()
|
add(db.getChapters(manga).createObservable()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.doOnNext(chapters -> {
|
.doOnNext(chapters -> {
|
||||||
stop(CHAPTER_STATUS_CHANGES);
|
|
||||||
this.chapters = chapters;
|
this.chapters = chapters;
|
||||||
EventBus.getDefault().postSticky(new ChapterCountEvent(chapters.size()));
|
EventBus.getDefault().postSticky(new ChapterCountEvent(chapters.size()));
|
||||||
for (Chapter chapter : chapters) {
|
for (Chapter chapter : chapters) {
|
||||||
|
@ -112,6 +98,7 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
|
||||||
})
|
})
|
||||||
.subscribe(chaptersSubject::onNext));
|
.subscribe(chaptersSubject::onNext));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void fetchChaptersFromSource() {
|
public void fetchChaptersFromSource() {
|
||||||
hasRequested = true;
|
hasRequested = true;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.mangafeed.ui.manga.info;
|
package eu.kanade.mangafeed.ui.manga.info;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -21,13 +22,15 @@ import nucleus.factory.RequiresPresenter;
|
||||||
@RequiresPresenter(MangaInfoPresenter.class)
|
@RequiresPresenter(MangaInfoPresenter.class)
|
||||||
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
||||||
|
|
||||||
@Bind(R.id.manga_artist) TextView mArtist;
|
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
|
||||||
@Bind(R.id.manga_author) TextView mAuthor;
|
|
||||||
@Bind(R.id.manga_chapters) TextView mChapters;
|
@Bind(R.id.manga_artist) TextView artist;
|
||||||
@Bind(R.id.manga_genres) TextView mGenres;
|
@Bind(R.id.manga_author) TextView author;
|
||||||
@Bind(R.id.manga_status) TextView mStatus;
|
@Bind(R.id.manga_chapters) TextView chapterCount;
|
||||||
@Bind(R.id.manga_summary) TextView mDescription;
|
@Bind(R.id.manga_genres) TextView genres;
|
||||||
@Bind(R.id.manga_cover) ImageView mCover;
|
@Bind(R.id.manga_status) TextView status;
|
||||||
|
@Bind(R.id.manga_summary) TextView description;
|
||||||
|
@Bind(R.id.manga_cover) ImageView cover;
|
||||||
|
|
||||||
@Bind(R.id.action_favorite) Button favoriteBtn;
|
@Bind(R.id.action_favorite) Button favoriteBtn;
|
||||||
|
|
||||||
|
@ -52,37 +55,63 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
||||||
favoriteBtn.setOnClickListener(v -> {
|
favoriteBtn.setOnClickListener(v -> {
|
||||||
getPresenter().toggleFavorite();
|
getPresenter().toggleFavorite();
|
||||||
});
|
});
|
||||||
|
swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMangaInfo(Manga manga) {
|
public void onNextManga(Manga manga) {
|
||||||
mArtist.setText(manga.artist);
|
if (manga.initialized) {
|
||||||
mAuthor.setText(manga.author);
|
setMangaInfo(manga);
|
||||||
mGenres.setText(manga.genre);
|
} else {
|
||||||
mStatus.setText("Ongoing"); //TODO
|
// Initialize manga
|
||||||
mDescription.setText(manga.description);
|
fetchMangaFromSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMangaInfo(Manga manga) {
|
||||||
|
artist.setText(manga.artist);
|
||||||
|
author.setText(manga.author);
|
||||||
|
genres.setText(manga.genre);
|
||||||
|
status.setText("Ongoing"); //TODO
|
||||||
|
description.setText(manga.description);
|
||||||
|
|
||||||
setFavoriteText(manga.favorite);
|
setFavoriteText(manga.favorite);
|
||||||
|
|
||||||
if (mCover.getDrawable() == null) {
|
|
||||||
CoverCache coverCache = getPresenter().coverCache;
|
CoverCache coverCache = getPresenter().coverCache;
|
||||||
LazyHeaders headers = getPresenter().source.getGlideHeaders();
|
LazyHeaders headers = getPresenter().source.getGlideHeaders();
|
||||||
|
if (manga.thumbnail_url != null && cover.getDrawable() == null) {
|
||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
coverCache.saveAndLoadFromCache(mCover, manga.thumbnail_url, headers);
|
coverCache.saveAndLoadFromCache(cover, manga.thumbnail_url, headers);
|
||||||
} else {
|
} else {
|
||||||
coverCache.loadFromNetwork(mCover, manga.thumbnail_url, headers);
|
coverCache.loadFromNetwork(cover, manga.thumbnail_url, headers);
|
||||||
}
|
}
|
||||||
|
cover.setTag(manga.thumbnail_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChapterCount(int count) {
|
public void setChapterCount(int count) {
|
||||||
mChapters.setText(String.valueOf(count));
|
chapterCount.setText(String.valueOf(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFavoriteText(boolean isFavorite) {
|
public void setFavoriteText(boolean isFavorite) {
|
||||||
favoriteBtn.setText(!isFavorite ? R.string.add_to_library : R.string.remove_from_library);
|
favoriteBtn.setText(!isFavorite ? R.string.add_to_library : R.string.remove_from_library);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchMangaFromSource() {
|
||||||
|
setRefreshing(true);
|
||||||
|
getPresenter().fetchMangaFromSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFetchMangaDone() {
|
||||||
|
setRefreshing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFetchMangaError() {
|
||||||
|
setRefreshing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRefreshing(boolean value) {
|
||||||
|
swipeRefresh.setRefreshing(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import eu.kanade.mangafeed.event.ChapterCountEvent;
|
||||||
import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
|
import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
|
||||||
import eu.kanade.mangafeed.util.EventBusHook;
|
import eu.kanade.mangafeed.util.EventBusHook;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
||||||
|
|
||||||
|
@ -24,8 +26,11 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
||||||
protected Source source;
|
protected Source source;
|
||||||
private int count = -1;
|
private int count = -1;
|
||||||
|
|
||||||
|
private boolean isFetching;
|
||||||
|
|
||||||
private static final int GET_MANGA = 1;
|
private static final int GET_MANGA = 1;
|
||||||
private static final int GET_CHAPTER_COUNT = 2;
|
private static final int GET_CHAPTER_COUNT = 2;
|
||||||
|
private static final int FETCH_MANGA_INFO = 3;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedState) {
|
protected void onCreate(Bundle savedState) {
|
||||||
|
@ -33,23 +38,24 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
||||||
|
|
||||||
restartableLatestCache(GET_MANGA,
|
restartableLatestCache(GET_MANGA,
|
||||||
() -> Observable.just(manga),
|
() -> Observable.just(manga),
|
||||||
MangaInfoFragment::setMangaInfo);
|
MangaInfoFragment::onNextManga);
|
||||||
|
|
||||||
restartableLatestCache(GET_CHAPTER_COUNT,
|
restartableLatestCache(GET_CHAPTER_COUNT,
|
||||||
() -> Observable.just(count),
|
() -> Observable.just(count),
|
||||||
MangaInfoFragment::setChapterCount);
|
MangaInfoFragment::setChapterCount);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
restartableFirst(FETCH_MANGA_INFO,
|
||||||
protected void onTakeView(MangaInfoFragment view) {
|
this::fetchMangaObs,
|
||||||
super.onTakeView(view);
|
(view, manga) -> view.onFetchMangaDone(),
|
||||||
|
(view, error) -> view.onFetchMangaError());
|
||||||
|
|
||||||
registerForStickyEvents();
|
registerForStickyEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDropView() {
|
protected void onDestroy() {
|
||||||
unregisterForEvents();
|
unregisterForEvents();
|
||||||
super.onDropView();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventBusHook
|
@EventBusHook
|
||||||
|
@ -67,9 +73,23 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initFavoriteText() {
|
public void fetchMangaFromSource() {
|
||||||
if (getView() != null)
|
if (!isFetching) {
|
||||||
getView().setFavoriteText(manga.favorite);
|
isFetching = true;
|
||||||
|
start(FETCH_MANGA_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Observable<Manga> fetchMangaObs() {
|
||||||
|
return source.pullMangaFromNetwork(manga.url)
|
||||||
|
.flatMap(networkManga -> {
|
||||||
|
Manga.copyFromNetwork(manga, networkManga);
|
||||||
|
db.insertManga(manga).executeAsBlocking();
|
||||||
|
return Observable.just(manga);
|
||||||
|
})
|
||||||
|
.finallyDo(() -> isFetching = false)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleFavorite() {
|
public void toggleFavorite() {
|
||||||
|
|
|
@ -3,10 +3,28 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context="eu.kanade.mangafeed.ui.catalogue.CatalogueFragment">
|
tools:context="eu.kanade.mangafeed.ui.catalogue.CatalogueFragment">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- It seems I have to wrap everything in SwipeRefreshLayout because it always take the entire height
|
||||||
|
and the description can't be seen.
|
||||||
|
Maybe with Relative layout it's better. We shouldn't put this layout inside the description layout
|
||||||
|
because the description should be scrollable and gestures could conflict with this layout.
|
||||||
|
Leaving it like this for now.
|
||||||
|
-->
|
||||||
|
<android.support.v4.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/swipe_refresh"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -206,3 +224,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</android.support.v4.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
Reference in a new issue