Update last chapter read in MAL when reaching the last page
This commit is contained in:
parent
e1a14be2bd
commit
9db81b1832
12 changed files with 183 additions and 20 deletions
|
@ -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">
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,12 @@ public class ChapterSyncManager {
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BaseChapterSync getSyncService(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case MYANIMELIST:
|
||||||
|
return myAnimeList;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Reference in a new issue