Use nucleus restartables in chapters presenter. Fix some database methods. Add swipe refresh to chapters fragment. Use Icepick library.

This commit is contained in:
inorichi 2015-10-18 19:18:50 +02:00
parent 920a71601b
commit 1719959bc8
10 changed files with 105 additions and 42 deletions

View File

@ -49,6 +49,7 @@ dependencies {
final MOCKITO_VERSION = '1.10.19' final MOCKITO_VERSION = '1.10.19'
final STORIO_VERSION = '1.4.0' final STORIO_VERSION = '1.4.0'
final NUCLEUS_VERSION = '2.0.1' final NUCLEUS_VERSION = '2.0.1'
final ICEPICK_VERSION = '3.1.0'
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
@ -75,6 +76,8 @@ dependencies {
compile 'com.jakewharton.timber:timber:3.1.0' compile 'com.jakewharton.timber:timber:3.1.0'
compile 'uk.co.ribot:easyadapter:1.5.0@aar' compile 'uk.co.ribot:easyadapter:1.5.0@aar'
compile 'ch.acra:acra:4.6.2' compile 'ch.acra:acra:4.6.2'
compile "frankiesardo:icepick:$ICEPICK_VERSION"
provided "frankiesardo:icepick-processor:$ICEPICK_VERSION"
compile "com.google.dagger:dagger:$DAGGER_VERSION" compile "com.google.dagger:dagger:$DAGGER_VERSION"
apt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" apt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"

View File

@ -94,3 +94,10 @@
-keep public class * extends android.support.v4.view.ActionProvider { -keep public class * extends android.support.v4.view.ActionProvider {
public <init>(android.content.Context); public <init>(android.content.Context);
} }
# Icepick
-dontwarn icepick.**
-keep class **$$Icepick { *; }
-keepclasseswithmembernames class * {
@icepick.* <fields>;
}

View File

@ -7,6 +7,7 @@ import com.pushtorefresh.storio.sqlite.StorIOSQLite;
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite; import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite;
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult; import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults; import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
import com.pushtorefresh.storio.sqlite.operations.post.PostResult;
import com.pushtorefresh.storio.sqlite.operations.put.PutResult; import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
import com.pushtorefresh.storio.sqlite.operations.put.PutResults; import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
@ -73,7 +74,7 @@ public class DatabaseHelper implements MangaManager, ChapterManager {
} }
@Override @Override
public Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters) { public Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters) {
return mChapterManager.insertOrRemoveChapters(manga, chapters); return mChapterManager.insertOrRemoveChapters(manga, chapters);
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.mangafeed.data.managers;
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult; import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults; import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
import com.pushtorefresh.storio.sqlite.operations.post.PostResult;
import com.pushtorefresh.storio.sqlite.operations.put.PutResult; import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
import com.pushtorefresh.storio.sqlite.operations.put.PutResults; import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
@ -21,7 +22,7 @@ public interface ChapterManager {
Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters); Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters);
Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters); Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters);
Observable<DeleteResult> deleteChapter(Chapter chapter); Observable<DeleteResult> deleteChapter(Chapter chapter);

View File

@ -70,6 +70,10 @@ public class ChapterManagerImpl extends BaseManager implements ChapterManager {
// Add new chapters or delete if the source deletes them // Add new chapters or delete if the source deletes them
@Override @Override
public Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters) { public Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters) {
for (Chapter chapter : chapters) {
chapter.manga_id = manga.id;
}
Observable<List<Chapter>> chapterList = Observable.create(subscriber -> { Observable<List<Chapter>> chapterList = Observable.create(subscriber -> {
subscriber.onNext(prepareGetChapters(manga).executeAsBlocking()); subscriber.onNext(prepareGetChapters(manga).executeAsBlocking());
subscriber.onCompleted(); subscriber.onCompleted();

View File

@ -1,11 +1,27 @@
package eu.kanade.mangafeed.presenter; package eu.kanade.mangafeed.presenter;
import android.os.Bundle;
import android.support.annotation.NonNull;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import icepick.Icepick;
import nucleus.presenter.RxPresenter; import nucleus.presenter.RxPresenter;
import nucleus.view.ViewWithPresenter; import nucleus.view.ViewWithPresenter;
public class BasePresenter<V extends ViewWithPresenter> extends RxPresenter<V> { public class BasePresenter<V extends ViewWithPresenter> extends RxPresenter<V> {
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
Icepick.restoreInstanceState(this, savedState);
}
@Override
protected void onSave(@NonNull Bundle state) {
super.onSave(state);
Icepick.saveInstanceState(this, state);
}
public void registerForStickyEvents() { public void registerForStickyEvents() {
EventBus.getDefault().registerSticky(this); EventBus.getDefault().registerSticky(this);
} }

View File

@ -1,15 +1,22 @@
package eu.kanade.mangafeed.presenter; package eu.kanade.mangafeed.presenter;
import android.os.Bundle;
import com.pushtorefresh.storio.sqlite.operations.post.PostResult;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import eu.kanade.mangafeed.data.helpers.DatabaseHelper; import eu.kanade.mangafeed.data.helpers.DatabaseHelper;
import eu.kanade.mangafeed.data.helpers.SourceManager; import eu.kanade.mangafeed.data.helpers.SourceManager;
import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.sources.Source;
import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment; import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment;
import rx.Subscription; import rx.Observable;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
import timber.log.Timber;
public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment> { public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment> {
@ -17,9 +24,24 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
@Inject SourceManager sourceManager; @Inject SourceManager sourceManager;
private Manga manga; private Manga manga;
private Subscription chaptersSubscription;
private Subscription onlineChaptersSubscription; private static final int DB_CHAPTERS = 1;
private boolean doingRequest = false; private static final int ONLINE_CHAPTERS = 2;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
restartableLatestCache(DB_CHAPTERS,
this::getDbChaptersObs,
MangaChaptersFragment::onNextChapters
);
restartableLatestCache(ONLINE_CHAPTERS,
this::getOnlineChaptersObs,
(view, result) -> view.onNextOnlineChapters()
);
}
@Override @Override
protected void onTakeView(MangaChaptersFragment view) { protected void onTakeView(MangaChaptersFragment view) {
@ -34,43 +56,30 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
} }
public void onEventMainThread(Manga manga) { public void onEventMainThread(Manga manga) {
if (this.manga == null) {
this.manga = manga; this.manga = manga;
getChapters(); start(DB_CHAPTERS);
}
} }
public void refreshChapters() { public void refreshChapters(MangaChaptersFragment view) {
if (manga != null && !doingRequest) if (manga != null) {
getChaptersFromSource(manga); view.setSwipeRefreshing();
start(ONLINE_CHAPTERS);
}
} }
public void getChapters() { private Observable<List<Chapter>> getDbChaptersObs() {
if (chaptersSubscription != null) return db.getChapters(manga.id)
return;
add(chaptersSubscription = db.getChapters(manga.id)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread());
.compose(deliverLatestCache())
.subscribe(this.split(MangaChaptersFragment::onNextChapters)));
} }
public void getChaptersFromSource(Manga manga) { private Observable<PostResult> getOnlineChaptersObs() {
if (onlineChaptersSubscription != null) return sourceManager.get(manga.source)
remove(onlineChaptersSubscription); .pullChaptersFromNetwork(manga.url)
Source source = sourceManager.get(manga.source);
doingRequest = true;
onlineChaptersSubscription = source.pullChaptersFromNetwork(manga.url)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters))
.compose(deliverLatestCache()) .observeOn(AndroidSchedulers.mainThread());
.subscribe(this.split((view, chapters) -> {
doingRequest = false;
}), throwable -> {
doingRequest = false;
});
add(onlineChaptersSubscription);
} }
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.mangafeed.ui.fragment;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -26,6 +27,7 @@ import uk.co.ribot.easyadapter.EasyRecyclerAdapter;
public class MangaChaptersFragment extends BaseFragment<MangaChaptersPresenter> { public class MangaChaptersFragment extends BaseFragment<MangaChaptersPresenter> {
@Bind(R.id.chapter_list) RecyclerView chapters; @Bind(R.id.chapter_list) RecyclerView chapters;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipe_refresh;
private EasyRecyclerAdapter<Chapter> adapter; private EasyRecyclerAdapter<Chapter> adapter;
@ -48,6 +50,7 @@ public class MangaChaptersFragment extends BaseFragment<MangaChaptersPresenter>
chapters.setLayoutManager(new LinearLayoutManager(getActivity())); chapters.setLayoutManager(new LinearLayoutManager(getActivity()));
createAdapter(); createAdapter();
setSwipeRefreshListener();
return view; return view;
} }
@ -62,7 +65,7 @@ public class MangaChaptersFragment extends BaseFragment<MangaChaptersPresenter>
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_refresh: case R.id.action_refresh:
getPresenter().refreshChapters(); getPresenter().refreshChapters(this);
break; break;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -73,8 +76,19 @@ public class MangaChaptersFragment extends BaseFragment<MangaChaptersPresenter>
chapters.setAdapter(adapter); chapters.setAdapter(adapter);
} }
private void setSwipeRefreshListener() {
swipe_refresh.setOnRefreshListener(() -> getPresenter().refreshChapters(this));
}
public void onNextChapters(List<Chapter> chapters) { public void onNextChapters(List<Chapter> chapters) {
adapter.setItems(chapters); adapter.setItems(chapters);
} }
public void onNextOnlineChapters() {
swipe_refresh.setRefreshing(false);
}
public void setSwipeRefreshing() {
swipe_refresh.setRefreshing(true);
}
} }

View File

@ -3,6 +3,11 @@
android:orientation="vertical" android:layout_width="match_parent" android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -10,4 +15,6 @@
</android.support.v7.widget.RecyclerView> </android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout> </LinearLayout>

View File

@ -16,5 +16,6 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
jcenter() jcenter()
maven {url "https://clojars.org/repo/"}
} }
} }