Improve info fragment. Other minor changes and fixes.

This commit is contained in:
inorichi 2015-12-05 02:05:42 +01:00
parent c52c567eae
commit eb10d77374
8 changed files with 328 additions and 274 deletions

View File

@ -25,7 +25,6 @@ import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.event.DownloadChaptersEvent;
import eu.kanade.mangafeed.util.DiskUtils;
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
import eu.kanade.mangafeed.util.UrlUtil;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
@ -182,8 +181,10 @@ public class DownloadManager {
return pageListObservable
.subscribeOn(Schedulers.io())
.doOnNext(pages -> download.setStatus(Download.DOWNLOADING))
.doOnNext(pages -> download.downloadedImages = 0)
.doOnNext(pages -> {
download.downloadedImages = 0;
download.setStatus(Download.DOWNLOADING);
})
// Get all the URLs to the source images, fetch pages if necessary
.flatMap(download.source::getAllImageUrlsFromPageList)
// 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
private String getImageFilename(Page page) {
String url = UrlUtil.getPath(page.getImageUrl());
return url.substring(
url.lastIndexOf("/") + 1,
url.length());
String url = page.getImageUrl();
return url.substring(url.lastIndexOf("/") + 1, url.length());
}
private boolean isImageDownloaded(File imagePath) {

View File

@ -39,10 +39,10 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> {
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();
Bundle args = new Bundle();
args.putInt(SOURCE_ID, source_id);
args.putInt(SOURCE_ID, sourceId);
fragment.setArguments(args);
return fragment;
}

View File

@ -105,6 +105,9 @@ public class DownloadPresenter extends BasePresenter<DownloadFragment> {
}
private void observePagesStatus(Download download, DownloadFragment view) {
// Initial update of the downloaded pages
view.updateDownloadedPages(download);
PublishSubject<Integer> pageStatusSubject = PublishSubject.create();
for (Page page : download.pages) {
if (page.getStatus() != Page.READY)

View File

@ -17,7 +17,6 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
@Inject DatabaseHelper db;
private long mangaId;
private Manga manga;
private static final int DB_MANGA = 1;
@ -25,19 +24,13 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
restartableLatestCache(DB_MANGA,
() -> getDbMangaObservable()
.doOnNext(manga -> this.manga = manga),
(view, manga) -> {
view.setManga(manga);
EventBus.getDefault().postSticky(manga);
});
restartableLatestCache(DB_MANGA, this::getDbMangaObservable, MangaActivity::setManga);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Avoid fragments receiving wrong manga
// Avoid new instances receiving wrong manga
EventBus.getDefault().removeStickyEvent(Manga.class);
}
@ -45,7 +38,8 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
return db.getManga(mangaId).createObservable()
.subscribeOn(Schedulers.io())
.flatMap(Observable::from)
.observeOn(AndroidSchedulers.mainThread());
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(manga -> EventBus.getDefault().postSticky(manga));
}
public void queryManga(long mangaId) {

View File

@ -56,61 +56,48 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
restartableLatestCache(DB_CHAPTERS,
this::getDbChaptersObs,
ChaptersFragment::onNextChapters
);
ChaptersFragment::onNextChapters);
restartableLatestCache(FETCH_CHAPTERS,
restartableFirst(FETCH_CHAPTERS,
this::getOnlineChaptersObs,
(view, result) -> view.onFetchChaptersDone(),
(view, error) -> view.onFetchChaptersError()
);
(view, error) -> view.onFetchChaptersError());
restartableLatestCache(CHAPTER_STATUS_CHANGES,
this::getChapterStatusObs,
(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();
}
@Override
protected void onDropView() {
unregisterForEvents();
super.onDropView();
}
@Override
protected void onDestroy() {
unregisterForEvents();
EventBus.getDefault().removeStickyEvent(ChapterCountEvent.class);
super.onDestroy();
}
@EventBusHook
public void onEventMainThread(Manga manga) {
if (this.manga != null)
return;
this.manga = manga;
source = sourceManager.get(manga.source);
start(DB_CHAPTERS);
add(db.getChapters(manga).createObservable()
.subscribeOn(Schedulers.io())
.doOnNext(chapters -> {
stop(CHAPTER_STATUS_CHANGES);
this.chapters = chapters;
EventBus.getDefault().postSticky(new ChapterCountEvent(chapters.size()));
for (Chapter chapter : chapters) {
setChapterStatus(chapter);
}
start(CHAPTER_STATUS_CHANGES);
})
.subscribe(chaptersSubject::onNext));
if (!isStarted(DB_CHAPTERS)) {
source = sourceManager.get(manga.source);
start(DB_CHAPTERS);
add(db.getChapters(manga).createObservable()
.subscribeOn(Schedulers.io())
.doOnNext(chapters -> {
this.chapters = chapters;
EventBus.getDefault().postSticky(new ChapterCountEvent(chapters.size()));
for (Chapter chapter : chapters) {
setChapterStatus(chapter);
}
start(CHAPTER_STATUS_CHANGES);
})
.subscribe(chaptersSubject::onNext));
}
}
public void fetchChaptersFromSource() {

View File

@ -1,6 +1,7 @@
package eu.kanade.mangafeed.ui.manga.info;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -21,13 +22,15 @@ import nucleus.factory.RequiresPresenter;
@RequiresPresenter(MangaInfoPresenter.class)
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
@Bind(R.id.manga_artist) TextView mArtist;
@Bind(R.id.manga_author) TextView mAuthor;
@Bind(R.id.manga_chapters) TextView mChapters;
@Bind(R.id.manga_genres) TextView mGenres;
@Bind(R.id.manga_status) TextView mStatus;
@Bind(R.id.manga_summary) TextView mDescription;
@Bind(R.id.manga_cover) ImageView mCover;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
@Bind(R.id.manga_artist) TextView artist;
@Bind(R.id.manga_author) TextView author;
@Bind(R.id.manga_chapters) TextView chapterCount;
@Bind(R.id.manga_genres) TextView genres;
@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;
@ -52,37 +55,63 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
favoriteBtn.setOnClickListener(v -> {
getPresenter().toggleFavorite();
});
swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
return view;
}
public void setMangaInfo(Manga manga) {
mArtist.setText(manga.artist);
mAuthor.setText(manga.author);
mGenres.setText(manga.genre);
mStatus.setText("Ongoing"); //TODO
mDescription.setText(manga.description);
public void onNextManga(Manga manga) {
if (manga.initialized) {
setMangaInfo(manga);
} else {
// Initialize manga
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);
if (mCover.getDrawable() == null) {
CoverCache coverCache = getPresenter().coverCache;
LazyHeaders headers = getPresenter().source.getGlideHeaders();
CoverCache coverCache = getPresenter().coverCache;
LazyHeaders headers = getPresenter().source.getGlideHeaders();
if (manga.thumbnail_url != null && cover.getDrawable() == null) {
if (manga.favorite) {
coverCache.saveAndLoadFromCache(mCover, manga.thumbnail_url, headers);
coverCache.saveAndLoadFromCache(cover, manga.thumbnail_url, headers);
} 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) {
mChapters.setText(String.valueOf(count));
chapterCount.setText(String.valueOf(count));
}
public void setFavoriteText(boolean isFavorite) {
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);
}
}

View File

@ -13,6 +13,8 @@ import eu.kanade.mangafeed.event.ChapterCountEvent;
import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
import eu.kanade.mangafeed.util.EventBusHook;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
@ -24,8 +26,11 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
protected Source source;
private int count = -1;
private boolean isFetching;
private static final int GET_MANGA = 1;
private static final int GET_CHAPTER_COUNT = 2;
private static final int FETCH_MANGA_INFO = 3;
@Override
protected void onCreate(Bundle savedState) {
@ -33,23 +38,24 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
restartableLatestCache(GET_MANGA,
() -> Observable.just(manga),
MangaInfoFragment::setMangaInfo);
MangaInfoFragment::onNextManga);
restartableLatestCache(GET_CHAPTER_COUNT,
() -> Observable.just(count),
MangaInfoFragment::setChapterCount);
}
@Override
protected void onTakeView(MangaInfoFragment view) {
super.onTakeView(view);
restartableFirst(FETCH_MANGA_INFO,
this::fetchMangaObs,
(view, manga) -> view.onFetchMangaDone(),
(view, error) -> view.onFetchMangaError());
registerForStickyEvents();
}
@Override
protected void onDropView() {
protected void onDestroy() {
unregisterForEvents();
super.onDropView();
super.onDestroy();
}
@EventBusHook
@ -67,9 +73,23 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
}
}
public void initFavoriteText() {
if (getView() != null)
getView().setFavoriteText(manga.favorite);
public void fetchMangaFromSource() {
if (!isFetching) {
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() {

View File

@ -3,206 +3,228 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context="eu.kanade.mangafeed.ui.catalogue.CatalogueFragment">
<LinearLayout
<!-- 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:layout_height="wrap_content"
android:padding="10dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bkg_shadow_img"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:padding="4dp">
<ImageView
android:id="@+id/manga_cover"
android:layout_width="138dp"
android:layout_height="190dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:scaleType="fitXY"
android:visibility="visible" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/grid_item_description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:paddingLeft="15.0dip">
<TextView
android:id="@+id/manga_author_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@+id/manga_genres_label"
android:layout_marginTop="5dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/author" />
<TextView
android:id="@+id/manga_author"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_author_label"
android:layout_toRightOf="@id/manga_author_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_artist_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@id/manga_genres_label"
android:layout_below="@id/manga_author_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/artist" />
<TextView
android:id="@+id/manga_artist"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_artist_label"
android:layout_toRightOf="@id/manga_artist_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_chapters_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/manga_artist_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/chapters" />
<TextView
android:id="@+id/manga_chapters"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_chapters_label"
android:layout_toRightOf="@id/manga_chapters_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_status_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@id/manga_genres_label"
android:layout_below="@id/manga_chapters_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/status" />
<TextView
android:id="@+id/manga_status"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_status_label"
android:layout_toRightOf="@id/manga_chapters_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_genres_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/manga_status_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/genres" />
<TextView
android:id="@+id/manga_genres"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/manga_genres_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<Button
android:id="@+id/action_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add_to_library" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
android:layout_height="match_parent">
<TextView
android:id="@+id/manga_summary_label"
style="@style/manga_detail_label"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false"
android:text="@string/description" />
android:clickable="true"
android:orientation="vertical">
<TextView
android:id="@+id/manga_summary"
style="@style/manga_detail_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bkg_shadow_img"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:padding="4dp">
<ImageView
android:id="@+id/manga_cover"
android:layout_width="138dp"
android:layout_height="190dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:scaleType="fitXY"
android:visibility="visible" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/grid_item_description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:paddingLeft="15.0dip">
<TextView
android:id="@+id/manga_author_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@+id/manga_genres_label"
android:layout_marginTop="5dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/author" />
<TextView
android:id="@+id/manga_author"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_author_label"
android:layout_toRightOf="@id/manga_author_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_artist_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@id/manga_genres_label"
android:layout_below="@id/manga_author_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/artist" />
<TextView
android:id="@+id/manga_artist"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_artist_label"
android:layout_toRightOf="@id/manga_artist_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_chapters_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/manga_artist_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/chapters" />
<TextView
android:id="@+id/manga_chapters"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_chapters_label"
android:layout_toRightOf="@id/manga_chapters_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_status_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@id/manga_genres_label"
android:layout_below="@id/manga_chapters_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/status" />
<TextView
android:id="@+id/manga_status"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/manga_status_label"
android:layout_toRightOf="@id/manga_chapters_label"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:singleLine="true" />
<TextView
android:id="@+id/manga_genres_label"
style="@style/manga_detail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/manga_status_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="@string/genres" />
<TextView
android:id="@+id/manga_genres"
style="@style/manga_detail_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/manga_genres_label"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<Button
android:id="@+id/action_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add_to_library" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/manga_summary_label"
style="@style/manga_detail_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false"
android:text="@string/description" />
<TextView
android:id="@+id/manga_summary"
style="@style/manga_detail_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="false" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>