From 9db81b1832c8ce8dead8867482f77ad7060d16c4 Mon Sep 17 00:00:00 2001 From: inorichi Date: Fri, 27 Nov 2015 00:51:18 +0100 Subject: [PATCH] Update last chapter read in MAL when reaching the last page --- app/src/main/AndroidManifest.xml | 3 + .../data/chaptersync/BaseChapterSync.java | 5 ++ .../data/chaptersync/ChapterSyncManager.java | 8 ++ .../data/chaptersync/MyAnimeList.java | 4 +- .../chaptersync/UpdateChapterSyncService.java | 77 +++++++++++++++++++ .../data/database/models/ChapterSync.java | 4 +- .../event/UpdateChapterSyncEvent.java | 17 ++++ .../injection/component/AppComponent.java | 2 + .../ui/base/activity/BaseRxActivity.java | 6 +- .../ui/base/fragment/BaseRxFragment.java | 6 +- .../ui/base/presenter/BasePresenter.java | 12 +++ .../mangafeed/ui/reader/ReaderPresenter.java | 59 +++++++++++--- 12 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f5eacd937f..11309792c2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,9 @@ + + diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/BaseChapterSync.java b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/BaseChapterSync.java index 90f7adc207..cd1403e47c 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/BaseChapterSync.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/BaseChapterSync.java @@ -1,5 +1,8 @@ package eu.kanade.mangafeed.data.chaptersync; +import com.squareup.okhttp.Response; + +import eu.kanade.mangafeed.data.database.models.ChapterSync; import rx.Observable; public abstract class BaseChapterSync { @@ -13,4 +16,6 @@ public abstract class BaseChapterSync { public abstract Observable login(String username, String password); public abstract boolean isLogged(); + + public abstract Observable update(ChapterSync chapter); } diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java index 73d219bf08..e38f3faa48 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java @@ -26,4 +26,12 @@ public class ChapterSyncManager { return services; } + public BaseChapterSync getSyncService(int id) { + switch (id) { + case MYANIMELIST: + return myAnimeList; + } + return null; + } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java index 4e26b31c1a..9786d04274 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java @@ -89,7 +89,7 @@ public class MyAnimeList extends BaseChapterSync { .map(entry -> { ChapterSync chapter = ChapterSync.create(this); 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; }) .toList(); @@ -111,7 +111,7 @@ public class MyAnimeList extends BaseChapterSync { .map(entry -> { ChapterSync chapter = ChapterSync.create(this); 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()); chapter.last_chapter_read = Integer.parseInt( entry.select("my_read_chapters").first().text()); diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java new file mode 100644 index 0000000000..c313355e1d --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java @@ -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(); + })); + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java b/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java index 2f4314e21a..7a0897bfb6 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java @@ -16,10 +16,10 @@ public class ChapterSync { public long manga_id; @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_SYNC_ID) - public long sync_id; + public int sync_id; @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID) - public long remote_id; + public int remote_id; @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_TITLE) public String title; diff --git a/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java b/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java new file mode 100644 index 0000000000..965e10bb14 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java @@ -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; + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java index 53c98da6d1..2b81f4f776 100644 --- a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java +++ b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java @@ -6,6 +6,7 @@ import javax.inject.Singleton; import dagger.Component; 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.sync.LibraryUpdateService; import eu.kanade.mangafeed.injection.module.AppModule; @@ -55,6 +56,7 @@ public interface AppComponent { void inject(LibraryUpdateService libraryUpdateService); void inject(DownloadService downloadService); + void inject(UpdateChapterSyncService updateChapterSyncService); Application application(); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseRxActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseRxActivity.java index bcc1aa0632..cfab9a3132 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseRxActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseRxActivity.java @@ -4,7 +4,7 @@ import android.os.Bundle; import android.support.annotation.NonNull; 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.ReflectionPresenterFactory; import nucleus.presenter.Presenter; @@ -60,7 +60,9 @@ public abstract class BaseRxActivity

extends BaseActivity i final PresenterFactory

superFactory = getPresenterFactory(); setPresenterFactory(() -> { P presenter = superFactory.createPresenter(); - ((App)getApplication()).getComponentReflection().inject(presenter); + App app = (App) getApplication(); + app.getComponentReflection().inject(presenter); + ((BasePresenter)presenter).setContext(app.getApplicationContext()); return presenter; }); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/base/fragment/BaseRxFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/base/fragment/BaseRxFragment.java index 15aaf34c1f..f8e811198f 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/base/fragment/BaseRxFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/base/fragment/BaseRxFragment.java @@ -3,7 +3,7 @@ package eu.kanade.mangafeed.ui.base.fragment; import android.os.Bundle; 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.ReflectionPresenterFactory; import nucleus.presenter.Presenter; @@ -57,7 +57,9 @@ public abstract class BaseRxFragment

extends BaseFragment i final PresenterFactory

superFactory = getPresenterFactory(); setPresenterFactory(() -> { 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; }); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/base/presenter/BasePresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/base/presenter/BasePresenter.java index 3023a7089e..c03a7703ce 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/base/presenter/BasePresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/base/presenter/BasePresenter.java @@ -1,5 +1,6 @@ package eu.kanade.mangafeed.ui.base.presenter; +import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; @@ -10,6 +11,8 @@ import nucleus.view.ViewWithPresenter; public class BasePresenter extends RxPresenter { + private Context context; + @Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); @@ -33,4 +36,13 @@ public class BasePresenter extends RxPresenter { public void unregisterForEvents() { EventBus.getDefault().unregister(this); } + + public void setContext(Context applicationContext) { + context = applicationContext; + } + + public Context getContext() { + return context; + } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java index 37e605d91e..f99cc28f6d 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java @@ -8,8 +8,12 @@ import java.util.List; import javax.inject.Inject; 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.models.Chapter; +import eu.kanade.mangafeed.data.database.models.ChapterSync; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.download.DownloadManager; 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.event.RetryPageEvent; import eu.kanade.mangafeed.event.SourceMangaChapterEvent; +import eu.kanade.mangafeed.event.UpdateChapterSyncEvent; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import eu.kanade.mangafeed.util.EventBusHook; import icepick.State; @@ -32,6 +37,7 @@ public class ReaderPresenter extends BasePresenter { @Inject PreferencesHelper prefs; @Inject DatabaseHelper db; @Inject DownloadManager downloadManager; + @Inject ChapterSyncManager syncManager; private Source source; private Manga manga; @@ -135,10 +141,47 @@ public class ReaderPresenter extends BasePresenter { } private void onChapterChange() { - if (pageList != null) { - if (!isDownloaded) - source.savePageList(chapter.url, pageList); - saveChapterProgress(); + if (pageList == null) + return; + + // 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 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 { 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() { if (nextChapterSubscription != null) remove(nextChapterSubscription);