Use a publisher to get manga details. Refactor CatalogueListPresenter

This commit is contained in:
inorichi 2015-10-13 21:27:29 +02:00
parent ed76520ebc
commit 8dc7c550ad
3 changed files with 98 additions and 66 deletions

View file

@ -1,6 +1,9 @@
package eu.kanade.mangafeed.presenter; package eu.kanade.mangafeed.presenter;
import android.content.Intent; import android.content.Intent;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -41,6 +44,7 @@ public class CatalogueListPresenter extends BasePresenter {
private Subscription mSearchViewSubscription; private Subscription mSearchViewSubscription;
private Subscription mMangaDetailFetchSubscription; private Subscription mMangaDetailFetchSubscription;
private PublishSubject<Observable<String>> mSearchViewPublishSubject; private PublishSubject<Observable<String>> mSearchViewPublishSubject;
private PublishSubject<Observable<List<Manga>>> mMangaDetailPublishSubject;
public CatalogueListPresenter(CatalogueListView view) { public CatalogueListPresenter(CatalogueListView view) {
@ -49,17 +53,79 @@ public class CatalogueListPresenter extends BasePresenter {
} }
public void initialize() { public void initialize() {
initializeSource();
initializeAdapter();
initializeSearch();
initializeMangaDetailsLoader();
getMangasFromSource(1);
}
private void initializeSource() {
int sourceId = view.getIntent().getIntExtra(Intent.EXTRA_UID, -1); int sourceId = view.getIntent().getIntExtra(Intent.EXTRA_UID, -1);
selectedSource = sourceManager.get(sourceId); selectedSource = sourceManager.get(sourceId);
view.setSourceTitle(selectedSource.getName()); view.setSourceTitle(selectedSource.getName());
}
private void initializeAdapter() {
adapter = new EasyAdapter<>(view.getActivity(), CatalogueListHolder.class); adapter = new EasyAdapter<>(view.getActivity(), CatalogueListHolder.class);
view.setAdapter(adapter); view.setAdapter(adapter);
view.setScrollListener(); view.setScrollListener();
}
initializeSearch(); private void initializeSearch() {
mSearchName = "";
mSearchMode = false;
mSearchViewPublishSubject = PublishSubject.create();
getMangasFromSource(1); mSearchViewSubscription = Observable.switchOnNext(mSearchViewPublishSubject)
.debounce(SEARCH_TIMEOUT, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
this::queryFromSearch,
error -> Timber.e(error.getCause(), error.getMessage()));
subscriptions.add(mSearchViewSubscription);
}
private void initializeMangaDetailsLoader() {
mMangaDetailPublishSubject = PublishSubject.create();
mMangaDetailFetchSubscription = Observable.switchOnNext(mMangaDetailPublishSubject)
.subscribeOn(Schedulers.io())
.flatMap(Observable::from)
.filter(manga -> !manga.initialized)
.buffer(5)
.concatMap(localMangas -> {
List<Observable<Manga>> mangaObservables = new ArrayList<>();
for (Manga manga : localMangas) {
Observable<Manga> tempObs = selectedSource.pullMangaFromNetwork(manga.url)
.subscribeOn(Schedulers.io())
.flatMap(networkManga -> {
Manga.copyFromNetwork(manga, networkManga);
db.insertMangaBlock(manga);
return Observable.just(manga);
});
mangaObservables.add(tempObs);
}
return Observable.merge(mangaObservables);
})
.filter(manga -> manga.initialized)
.onBackpressureBuffer()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(manga -> {
// Get manga index in the adapter
int index = getMangaIndex(manga);
// Get the image view associated with the manga.
// If it's null (not visible in the screen) there's no need to update the image.
ImageView imageView = view.getImageView(index);
if (imageView != null) {
updateImage(imageView, manga.thumbnail_url);
}
});
subscriptions.add(mMangaDetailFetchSubscription);
} }
public void getMangasFromSource(int page) { public void getMangasFromSource(int page) {
@ -73,7 +139,7 @@ public class CatalogueListPresenter extends BasePresenter {
.toList() .toList()
.subscribe(newMangas -> { .subscribe(newMangas -> {
adapter.addItems(newMangas); adapter.addItems(newMangas);
getMangaDetails(newMangas); mMangaDetailPublishSubject.onNext(Observable.just(newMangas));
}); });
subscriptions.add(mMangaFetchSubscription); subscriptions.add(mMangaFetchSubscription);
@ -90,7 +156,7 @@ public class CatalogueListPresenter extends BasePresenter {
.toList() .toList()
.subscribe(newMangas -> { .subscribe(newMangas -> {
adapter.addItems(newMangas); adapter.addItems(newMangas);
getMangaDetails(newMangas); mMangaDetailPublishSubject.onNext(Observable.just(newMangas));
}); });
subscriptions.add(mMangaSearchSubscription); subscriptions.add(mMangaSearchSubscription);
@ -105,61 +171,11 @@ public class CatalogueListPresenter extends BasePresenter {
return localManga; return localManga;
} }
private void getMangaDetails(List<Manga> mangas) {
subscriptions.remove(mMangaDetailFetchSubscription);
mMangaDetailFetchSubscription = Observable.from(mangas)
.subscribeOn(Schedulers.io())
.filter(manga -> !manga.initialized)
.buffer(3)
.concatMap(localMangas -> {
List<Observable<Manga>> mangaObservables = new ArrayList<>();
for (Manga manga : localMangas) {
Observable<Manga> tempObs = selectedSource.pullMangaFromNetwork(manga.url)
.flatMap(networkManga -> {
Manga.copyFromNetwork(manga, networkManga);
db.insertMangaBlock(manga);
return Observable.just(manga);
})
.subscribeOn(Schedulers.io());
mangaObservables.add(tempObs);
}
return Observable.merge(mangaObservables);
})
.filter(manga -> manga.initialized)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(manga -> {
int i;
for (i = 0; i < adapter.getCount(); i++) {
if (manga.id == adapter.getItem(i).id) {
break;
}
}
view.updateImage(i, manga.thumbnail_url);
});
subscriptions.add(mMangaDetailFetchSubscription);
}
public void onQueryTextChange(String query) { public void onQueryTextChange(String query) {
if (mSearchViewPublishSubject != null) if (mSearchViewPublishSubject != null)
mSearchViewPublishSubject.onNext(Observable.just(query)); mSearchViewPublishSubject.onNext(Observable.just(query));
} }
private void initializeSearch() {
mSearchName = "";
mSearchMode = false;
mSearchViewPublishSubject = PublishSubject.create();
mSearchViewSubscription = Observable.switchOnNext(mSearchViewPublishSubject)
.debounce(SEARCH_TIMEOUT, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
this::queryFromSearch,
error -> Timber.e(error.getCause(), error.getMessage()));
subscriptions.add(mSearchViewSubscription);
}
private void queryFromSearch(String query) { private void queryFromSearch(String query) {
// If search button clicked // If search button clicked
@ -189,4 +205,21 @@ public class CatalogueListPresenter extends BasePresenter {
} }
} }
private int getMangaIndex(Manga manga) {
int i;
for (i = 0; i < adapter.getCount(); i++) {
if (manga.id == adapter.getItem(i).id) {
return i;
}
}
return -1;
}
private void updateImage(ImageView imageView, String thumbnail) {
Glide.with(view.getActivity())
.load(thumbnail)
.centerCrop()
.into(imageView);
}
} }

View file

@ -8,8 +8,6 @@ import android.view.View;
import android.widget.GridView; import android.widget.GridView;
import android.widget.ImageView; import android.widget.ImageView;
import com.bumptech.glide.Glide;
import butterknife.Bind; import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.R;
@ -72,14 +70,19 @@ public class CatalogueListActivity extends BaseActivity implements CatalogueList
}); });
} }
// CatalogueListView
@Override
public void setSourceTitle(String title) { public void setSourceTitle(String title) {
setToolbarTitle(title); setToolbarTitle(title);
} }
@Override
public void setAdapter(EasyAdapter adapter) { public void setAdapter(EasyAdapter adapter) {
manga_list.setAdapter(adapter); manga_list.setAdapter(adapter);
} }
@Override
public void setScrollListener() { public void setScrollListener() {
scrollListener = new EndlessScrollListener() { scrollListener = new EndlessScrollListener() {
@Override @Override
@ -92,23 +95,19 @@ public class CatalogueListActivity extends BaseActivity implements CatalogueList
manga_list.setOnScrollListener(scrollListener); manga_list.setOnScrollListener(scrollListener);
} }
@Override
public void resetScrollListener() { public void resetScrollListener() {
scrollListener.resetScroll(); scrollListener.resetScroll();
} }
@Override @Override
public void updateImage(int position, String thumbnail) { public ImageView getImageView(int position) {
View v = manga_list.getChildAt(position - View v = manga_list.getChildAt(position -
manga_list.getFirstVisiblePosition()); manga_list.getFirstVisiblePosition());
if(v == null) if(v == null)
return; return null;
ImageView imageView = (ImageView) v.findViewById(R.id.catalogue_thumbnail); return (ImageView) v.findViewById(R.id.catalogue_thumbnail);
Glide.with(getActivity())
.load(thumbnail)
.centerCrop()
.into(imageView);
} }
} }

View file

@ -1,8 +1,8 @@
package eu.kanade.mangafeed.view; package eu.kanade.mangafeed.view;
import android.content.Intent; import android.content.Intent;
import android.widget.ImageView;
import eu.kanade.mangafeed.sources.Source;
import uk.co.ribot.easyadapter.EasyAdapter; import uk.co.ribot.easyadapter.EasyAdapter;
public interface CatalogueListView extends BaseView { public interface CatalogueListView extends BaseView {
@ -11,5 +11,5 @@ public interface CatalogueListView extends BaseView {
void setAdapter(EasyAdapter adapter); void setAdapter(EasyAdapter adapter);
void setScrollListener(); void setScrollListener();
void resetScrollListener(); void resetScrollListener();
void updateImage(int position, String thumbnail); ImageView getImageView(int position);
} }