Update last chapter read in MAL when reaching the last page

This commit is contained in:
inorichi 2015-11-27 00:51:18 +01:00
parent e1a14be2bd
commit 9db81b1832
12 changed files with 183 additions and 20 deletions

View file

@ -46,6 +46,9 @@
<service android:name=".data.download.DownloadService" <service android:name=".data.download.DownloadService"
android:exported="false"/> android:exported="false"/>
<service android:name=".data.chaptersync.UpdateChapterSyncService"
android:exported="false"/>
<receiver <receiver
android:name=".data.sync.LibraryUpdateService$SyncOnConnectionAvailable" android:name=".data.sync.LibraryUpdateService$SyncOnConnectionAvailable"
android:enabled="false"> android:enabled="false">

View file

@ -1,5 +1,8 @@
package eu.kanade.mangafeed.data.chaptersync; package eu.kanade.mangafeed.data.chaptersync;
import com.squareup.okhttp.Response;
import eu.kanade.mangafeed.data.database.models.ChapterSync;
import rx.Observable; import rx.Observable;
public abstract class BaseChapterSync { public abstract class BaseChapterSync {
@ -13,4 +16,6 @@ public abstract class BaseChapterSync {
public abstract Observable<Boolean> login(String username, String password); public abstract Observable<Boolean> login(String username, String password);
public abstract boolean isLogged(); public abstract boolean isLogged();
public abstract Observable<Response> update(ChapterSync chapter);
} }

View file

@ -26,4 +26,12 @@ public class ChapterSyncManager {
return services; return services;
} }
public BaseChapterSync getSyncService(int id) {
switch (id) {
case MYANIMELIST:
return myAnimeList;
}
return null;
}
} }

View file

@ -89,7 +89,7 @@ public class MyAnimeList extends BaseChapterSync {
.map(entry -> { .map(entry -> {
ChapterSync chapter = ChapterSync.create(this); ChapterSync chapter = ChapterSync.create(this);
chapter.title = entry.select("title").first().text(); chapter.title = entry.select("title").first().text();
chapter.remote_id = Long.parseLong(entry.select("id").first().text()); chapter.remote_id = Integer.parseInt(entry.select("id").first().text());
return chapter; return chapter;
}) })
.toList(); .toList();
@ -111,7 +111,7 @@ public class MyAnimeList extends BaseChapterSync {
.map(entry -> { .map(entry -> {
ChapterSync chapter = ChapterSync.create(this); ChapterSync chapter = ChapterSync.create(this);
chapter.title = entry.select("series_title").first().text(); chapter.title = entry.select("series_title").first().text();
chapter.remote_id = Long.parseLong( chapter.remote_id = Integer.parseInt(
entry.select("series_mangadb_id").first().text()); entry.select("series_mangadb_id").first().text());
chapter.last_chapter_read = Integer.parseInt( chapter.last_chapter_read = Integer.parseInt(
entry.select("my_read_chapters").first().text()); entry.select("my_read_chapters").first().text());

View file

@ -0,0 +1,77 @@
package eu.kanade.mangafeed.data.chaptersync;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import javax.inject.Inject;
import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.data.database.DatabaseHelper;
import eu.kanade.mangafeed.data.database.models.ChapterSync;
import eu.kanade.mangafeed.data.network.NetworkHelper;
import eu.kanade.mangafeed.event.UpdateChapterSyncEvent;
import eu.kanade.mangafeed.util.EventBusHook;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
public class UpdateChapterSyncService extends Service {
@Inject ChapterSyncManager syncManager;
@Inject NetworkHelper networkManager;
@Inject DatabaseHelper db;
private CompositeSubscription subscriptions;
public static void start(Context context) {
context.startService(new Intent(context, UpdateChapterSyncService.class));
}
@Override
public void onCreate() {
super.onCreate();
App.get(this).getComponent().inject(this);
subscriptions = new CompositeSubscription();
EventBus.getDefault().registerSticky(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
subscriptions.unsubscribe();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@EventBusHook
public void onEventMainThread(UpdateChapterSyncEvent event) {
updateLastChapteRead(event.getChapterSync());
}
private void updateLastChapteRead(ChapterSync chapterSync) {
BaseChapterSync sync = syncManager.getSyncService(chapterSync.sync_id);
subscriptions.add(sync.update(chapterSync)
.flatMap(response -> db.insertChapterSync(chapterSync).createObservable())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
stopSelf();
}, error -> {
stopSelf();
}));
}
}

View file

@ -16,10 +16,10 @@ public class ChapterSync {
public long manga_id; public long manga_id;
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_SYNC_ID) @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_SYNC_ID)
public long sync_id; public int sync_id;
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID) @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID)
public long remote_id; public int remote_id;
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_TITLE) @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_TITLE)
public String title; public String title;

View file

@ -0,0 +1,17 @@
package eu.kanade.mangafeed.event;
import eu.kanade.mangafeed.data.database.models.ChapterSync;
public class UpdateChapterSyncEvent {
private ChapterSync chapterSync;
public UpdateChapterSyncEvent(ChapterSync chapterSync) {
this.chapterSync = chapterSync;
}
public ChapterSync getChapterSync() {
return chapterSync;
}
}

View file

@ -6,6 +6,7 @@ import javax.inject.Singleton;
import dagger.Component; import dagger.Component;
import eu.kanade.mangafeed.data.chaptersync.MyAnimeList; import eu.kanade.mangafeed.data.chaptersync.MyAnimeList;
import eu.kanade.mangafeed.data.chaptersync.UpdateChapterSyncService;
import eu.kanade.mangafeed.data.download.DownloadService; import eu.kanade.mangafeed.data.download.DownloadService;
import eu.kanade.mangafeed.data.sync.LibraryUpdateService; import eu.kanade.mangafeed.data.sync.LibraryUpdateService;
import eu.kanade.mangafeed.injection.module.AppModule; import eu.kanade.mangafeed.injection.module.AppModule;
@ -55,6 +56,7 @@ public interface AppComponent {
void inject(LibraryUpdateService libraryUpdateService); void inject(LibraryUpdateService libraryUpdateService);
void inject(DownloadService downloadService); void inject(DownloadService downloadService);
void inject(UpdateChapterSyncService updateChapterSyncService);
Application application(); Application application();

View file

@ -4,7 +4,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import eu.kanade.mangafeed.App; import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.ui.base.activity.BaseActivity; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
import nucleus.factory.PresenterFactory; import nucleus.factory.PresenterFactory;
import nucleus.factory.ReflectionPresenterFactory; import nucleus.factory.ReflectionPresenterFactory;
import nucleus.presenter.Presenter; import nucleus.presenter.Presenter;
@ -60,7 +60,9 @@ public abstract class BaseRxActivity<P extends Presenter> extends BaseActivity i
final PresenterFactory<P> superFactory = getPresenterFactory(); final PresenterFactory<P> superFactory = getPresenterFactory();
setPresenterFactory(() -> { setPresenterFactory(() -> {
P presenter = superFactory.createPresenter(); P presenter = superFactory.createPresenter();
((App)getApplication()).getComponentReflection().inject(presenter); App app = (App) getApplication();
app.getComponentReflection().inject(presenter);
((BasePresenter)presenter).setContext(app.getApplicationContext());
return presenter; return presenter;
}); });

View file

@ -3,7 +3,7 @@ package eu.kanade.mangafeed.ui.base.fragment;
import android.os.Bundle; import android.os.Bundle;
import eu.kanade.mangafeed.App; import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.ui.base.fragment.BaseFragment; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter;
import nucleus.factory.PresenterFactory; import nucleus.factory.PresenterFactory;
import nucleus.factory.ReflectionPresenterFactory; import nucleus.factory.ReflectionPresenterFactory;
import nucleus.presenter.Presenter; import nucleus.presenter.Presenter;
@ -57,7 +57,9 @@ public abstract class BaseRxFragment<P extends Presenter> extends BaseFragment i
final PresenterFactory<P> superFactory = getPresenterFactory(); final PresenterFactory<P> superFactory = getPresenterFactory();
setPresenterFactory(() -> { setPresenterFactory(() -> {
P presenter = superFactory.createPresenter(); P presenter = superFactory.createPresenter();
((App)getActivity().getApplication()).getComponentReflection().inject(presenter); App app = (App) getActivity().getApplication();
app.getComponentReflection().inject(presenter);
((BasePresenter)presenter).setContext(app.getApplicationContext());
return presenter; return presenter;
}); });

View file

@ -1,5 +1,6 @@
package eu.kanade.mangafeed.ui.base.presenter; package eu.kanade.mangafeed.ui.base.presenter;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -10,6 +11,8 @@ import nucleus.view.ViewWithPresenter;
public class BasePresenter<V extends ViewWithPresenter> extends RxPresenter<V> { public class BasePresenter<V extends ViewWithPresenter> extends RxPresenter<V> {
private Context context;
@Override @Override
protected void onCreate(Bundle savedState) { protected void onCreate(Bundle savedState) {
super.onCreate(savedState); super.onCreate(savedState);
@ -33,4 +36,13 @@ public class BasePresenter<V extends ViewWithPresenter> extends RxPresenter<V> {
public void unregisterForEvents() { public void unregisterForEvents() {
EventBus.getDefault().unregister(this); EventBus.getDefault().unregister(this);
} }
public void setContext(Context applicationContext) {
context = applicationContext;
}
public Context getContext() {
return context;
}
} }

View file

@ -8,8 +8,12 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager;
import eu.kanade.mangafeed.data.chaptersync.MyAnimeList;
import eu.kanade.mangafeed.data.chaptersync.UpdateChapterSyncService;
import eu.kanade.mangafeed.data.database.DatabaseHelper; import eu.kanade.mangafeed.data.database.DatabaseHelper;
import eu.kanade.mangafeed.data.database.models.Chapter; import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.ChapterSync;
import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.download.DownloadManager; import eu.kanade.mangafeed.data.download.DownloadManager;
import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.data.preference.PreferencesHelper;
@ -17,6 +21,7 @@ import eu.kanade.mangafeed.data.source.base.Source;
import eu.kanade.mangafeed.data.source.model.Page; import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.event.RetryPageEvent; import eu.kanade.mangafeed.event.RetryPageEvent;
import eu.kanade.mangafeed.event.SourceMangaChapterEvent; import eu.kanade.mangafeed.event.SourceMangaChapterEvent;
import eu.kanade.mangafeed.event.UpdateChapterSyncEvent;
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 icepick.State; import icepick.State;
@ -32,6 +37,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
@Inject PreferencesHelper prefs; @Inject PreferencesHelper prefs;
@Inject DatabaseHelper db; @Inject DatabaseHelper db;
@Inject DownloadManager downloadManager; @Inject DownloadManager downloadManager;
@Inject ChapterSyncManager syncManager;
private Source source; private Source source;
private Manga manga; private Manga manga;
@ -135,10 +141,47 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
} }
private void onChapterChange() { private void onChapterChange() {
if (pageList != null) { if (pageList == null)
if (!isDownloaded) return;
source.savePageList(chapter.url, pageList);
saveChapterProgress(); // Cache page list for online chapters to allow a faster reopen
if (!isDownloaded)
source.savePageList(chapter.url, pageList);
// Save current progress of the chapter. Mark as read if the chapter is finished
// and update progress in remote services (like MyAnimeList)
chapter.last_page_read = currentPage;
if (isChapterFinished()) {
chapter.read = true;
updateChapterSyncLastChapterRead();
}
db.insertChapter(chapter).executeAsBlocking();
}
private boolean isChapterFinished() {
return !chapter.read && currentPage == pageList.size() - 1;
}
private void updateChapterSyncLastChapterRead() {
// TODO don't use MAL methods for possible alternatives to MAL
MyAnimeList mal = syncManager.getMyAnimeList();
if (!mal.isLogged())
return;
List<ChapterSync> result = db.getChapterSync(manga, mal).executeAsBlocking();
if (result.isEmpty())
return;
ChapterSync chapterSync = result.get(0);
int lastChapterReadLocal = (int) Math.floor(chapter.chapter_number);
int lastChapterReadRemote = chapterSync.last_chapter_read;
if (lastChapterReadLocal > lastChapterReadRemote) {
chapterSync.last_chapter_read = lastChapterReadLocal;
EventBus.getDefault().postSticky(new UpdateChapterSyncEvent(chapterSync));
UpdateChapterSyncService.start(getContext());
} }
} }
@ -186,14 +229,6 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
this.currentPage = currentPage; this.currentPage = currentPage;
} }
private void saveChapterProgress() {
chapter.last_page_read = currentPage;
if (currentPage == pageList.size() - 1) {
chapter.read = true;
}
db.insertChapter(chapter).executeAsBlocking();
}
private void getAdjacentChapters() { private void getAdjacentChapters() {
if (nextChapterSubscription != null) if (nextChapterSubscription != null)
remove(nextChapterSubscription); remove(nextChapterSubscription);