Rewrite the chapter insertion method. Create a wakelock until the library updates. Move custom preferences to widget package.

This commit is contained in:
inorichi 2016-01-10 19:49:26 +01:00
parent fcb5bf4dd4
commit e702be1a8d
18 changed files with 84 additions and 107 deletions

View File

@ -1,6 +1,7 @@
package eu.kanade.mangafeed.data.database; package eu.kanade.mangafeed.data.database;
import android.content.Context; import android.content.Context;
import android.util.Pair;
import com.pushtorefresh.storio.Queries; import com.pushtorefresh.storio.Queries;
import com.pushtorefresh.storio.sqlite.StorIOSQLite; import com.pushtorefresh.storio.sqlite.StorIOSQLite;
@ -12,11 +13,11 @@ import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects;
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject; import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject;
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects; import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects;
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutObject; import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutObject;
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery; import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
import com.pushtorefresh.storio.sqlite.queries.Query; import com.pushtorefresh.storio.sqlite.queries.Query;
import com.pushtorefresh.storio.sqlite.queries.RawQuery; import com.pushtorefresh.storio.sqlite.queries.RawQuery;
import java.util.Date;
import java.util.List; import java.util.List;
import eu.kanade.mangafeed.data.database.models.Category; import eu.kanade.mangafeed.data.database.models.Category;
@ -37,7 +38,6 @@ import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
import eu.kanade.mangafeed.data.database.tables.MangaTable; import eu.kanade.mangafeed.data.database.tables.MangaTable;
import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService; import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService;
import eu.kanade.mangafeed.util.ChapterRecognition; import eu.kanade.mangafeed.util.ChapterRecognition;
import eu.kanade.mangafeed.util.PostResult;
import rx.Observable; import rx.Observable;
public class DatabaseHelper { public class DatabaseHelper {
@ -246,37 +246,46 @@ public class DatabaseHelper {
} }
// Add new chapters or delete if the source deletes them // Add new chapters or delete if the source deletes them
public Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters) { public Observable<Pair<Integer, Integer>> insertOrRemoveChapters(Manga manga, List<Chapter> sourceChapters) {
for (Chapter chapter : chapters) { List<Chapter> dbChapters = getChapters(manga).executeAsBlocking();
chapter.manga_id = manga.id;
}
Observable<List<Chapter>> chapterList = Observable.create(subscriber -> { Observable<List<Chapter>> newChapters = Observable.from(sourceChapters)
subscriber.onNext(getChapters(manga).executeAsBlocking()); .filter(c -> !dbChapters.contains(c))
subscriber.onCompleted(); .doOnNext(c -> {
c.manga_id = manga.id;
c.date_fetch = new Date().getTime();
ChapterRecognition.parseChapterNumber(c, manga);
})
.toList();
Observable<List<Chapter>> deletedChapters = Observable.from(dbChapters)
.filter(c -> !sourceChapters.contains(c))
.toList();
return Observable.zip(newChapters, deletedChapters, (toAdd, toDelete) -> {
int added = 0;
int deleted = 0;
db.internal().beginTransaction();
try {
if (!toAdd.isEmpty()) {
// Set the date fetch for new items in reverse order to allow another sorting method.
// Sources MUST return the chapters from most to less recent, which is common.
for (int i = toAdd.size() - 1; i >= 0; i--) {
toAdd.get(i).date_fetch = new Date().getTime();
}
added = insertChapters(toAdd).executeAsBlocking().numberOfInserts();
}
if (!toDelete.isEmpty()) {
deleted = deleteChapters(toDelete).executeAsBlocking().results().size();
}
db.internal().setTransactionSuccessful();
} finally {
db.internal().endTransaction();
}
return Pair.create(added, deleted);
}); });
Observable<Integer> newChaptersObs = chapterList
.flatMap(dbChapters -> Observable.from(chapters)
.filter(c -> !dbChapters.contains(c))
.map(c -> {
ChapterRecognition.parseChapterNumber(c, manga);
return c;
})
.toList()
.flatMap(newChapters -> insertChapters(newChapters).createObservable())
.map(PutResults::numberOfInserts));
Observable<Integer> deletedChaptersObs = chapterList
.flatMap(dbChapters -> Observable.from(dbChapters)
.filter(c -> !chapters.contains(c))
.toList()
.flatMap(deletedChapters -> deleteChapters(deletedChapters).createObservable())
.map(d -> d.results().size()));
return Observable.zip(newChaptersObs, deletedChaptersObs,
(insertions, deletions) -> new PostResult(0, insertions, deletions)
);
} }
public PreparedDeleteObject<Chapter> deleteChapter(Chapter chapter) { public PreparedDeleteObject<Chapter> deleteChapter(Chapter chapter) {

View File

@ -232,8 +232,6 @@ public class Batoto extends LoginSource {
if (dateElement != null) { if (dateElement != null) {
chapter.date_upload = parseDateFromElement(dateElement); chapter.date_upload = parseDateFromElement(dateElement);
} }
chapter.date_fetch = new Date().getTime();
return chapter; return chapter;
} }

View File

@ -14,7 +14,6 @@ import org.jsoup.nodes.Element;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -194,8 +193,6 @@ public class Kissmanga extends Source {
chapter.date_upload = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(date).getTime(); chapter.date_upload = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(date).getTime();
} catch (ParseException e) { /* Ignore */ } } catch (ParseException e) { /* Ignore */ }
} }
chapter.date_fetch = new Date().getTime();
return chapter; return chapter;
} }

View File

@ -174,8 +174,6 @@ public class Mangafox extends Source {
if (dateElement != null) { if (dateElement != null) {
chapter.date_upload = parseUpdateFromElement(dateElement); chapter.date_upload = parseUpdateFromElement(dateElement);
} }
chapter.date_fetch = new Date().getTime();
return chapter; return chapter;
} }

View File

@ -234,8 +234,6 @@ public class Mangahere extends Source {
if (dateElement != null) { if (dateElement != null) {
chapter.date_upload = parseDateFromElement(dateElement); chapter.date_upload = parseDateFromElement(dateElement);
} }
chapter.date_fetch = new Date().getTime();
return chapter; return chapter;
} }

View File

@ -5,6 +5,8 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager;
import android.util.Pair;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -22,7 +24,6 @@ import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.util.AndroidComponentUtil; import eu.kanade.mangafeed.util.AndroidComponentUtil;
import eu.kanade.mangafeed.util.NetworkUtil; import eu.kanade.mangafeed.util.NetworkUtil;
import eu.kanade.mangafeed.util.NotificationUtil; import eu.kanade.mangafeed.util.NotificationUtil;
import eu.kanade.mangafeed.util.PostResult;
import rx.Observable; import rx.Observable;
import rx.Subscription; import rx.Subscription;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
@ -34,6 +35,7 @@ public class LibraryUpdateService extends Service {
@Inject SourceManager sourceManager; @Inject SourceManager sourceManager;
@Inject PreferencesHelper preferences; @Inject PreferencesHelper preferences;
private PowerManager.WakeLock wakeLock;
private Subscription subscription; private Subscription subscription;
public static final int UPDATE_NOTIFICATION_ID = 1; public static final int UPDATE_NOTIFICATION_ID = 1;
@ -56,6 +58,7 @@ public class LibraryUpdateService extends Service {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
App.get(this).getComponent().inject(this); App.get(this).getComponent().inject(this);
createAndAcquireWakeLock();
} }
@Override @Override
@ -64,6 +67,7 @@ public class LibraryUpdateService extends Service {
subscription.unsubscribe(); subscription.unsubscribe();
// Reset the alarm // Reset the alarm
LibraryUpdateAlarm.startAlarm(this); LibraryUpdateAlarm.startAlarm(this);
destroyWakeLock();
super.onDestroy(); super.onDestroy();
} }
@ -111,17 +115,18 @@ public class LibraryUpdateService extends Service {
.concatMap(manga -> updateManga(manga) .concatMap(manga -> updateManga(manga)
.onErrorReturn(error -> { .onErrorReturn(error -> {
failedUpdates.add(manga); failedUpdates.add(manga);
return new PostResult(0, 0, 0); return Pair.create(0, 0);
}) })
.filter(result -> result.getNumberOfRowsInserted() > 0) // Filter out mangas without new chapters
.map(result -> new MangaUpdate(manga, result))) .filter(pair -> pair.first > 0)
.map(pair -> new MangaUpdate(manga, pair.first)))
.doOnNext(updates::add) .doOnNext(updates::add)
.doOnCompleted(() -> NotificationUtil.createBigText(this, UPDATE_NOTIFICATION_ID, .doOnCompleted(() -> NotificationUtil.createBigText(this, UPDATE_NOTIFICATION_ID,
getString(R.string.notification_update_completed), getString(R.string.notification_update_completed),
getUpdatedMangas(updates, failedUpdates))); getUpdatedMangas(updates, failedUpdates)));
} }
private Observable<PostResult> updateManga(Manga manga) { private Observable<Pair<Integer, Integer>> updateManga(Manga manga) {
return sourceManager.get(manga.source) return sourceManager.get(manga.source)
.pullChaptersFromNetwork(manga.url) .pullChaptersFromNetwork(manga.url)
.flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters)); .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters));
@ -135,7 +140,7 @@ public class LibraryUpdateService extends Service {
result.append(getString(R.string.notification_new_chapters)); result.append(getString(R.string.notification_new_chapters));
for (MangaUpdate update : updates) { for (MangaUpdate update : updates) {
result.append("\n").append(update.getManga().title); result.append("\n").append(update.manga.title);
} }
} }
if (!failedUpdates.isEmpty()) { if (!failedUpdates.isEmpty()) {
@ -154,6 +159,19 @@ public class LibraryUpdateService extends Service {
return null; return null;
} }
private void createAndAcquireWakeLock() {
wakeLock = ((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock");
wakeLock.acquire();
}
private void destroyWakeLock() {
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
wakeLock = null;
}
}
public static class SyncOnConnectionAvailable extends BroadcastReceiver { public static class SyncOnConnectionAvailable extends BroadcastReceiver {
@Override @Override
@ -169,20 +187,12 @@ public class LibraryUpdateService extends Service {
} }
private static class MangaUpdate { private static class MangaUpdate {
private Manga manga; public Manga manga;
private PostResult result; public int newChapters;
public MangaUpdate(Manga manga, PostResult result) { public MangaUpdate(Manga manga, int newChapters) {
this.manga = manga; this.manga = manga;
this.result = result; this.newChapters = newChapters;
}
public Manga getManga() {
return manga;
}
public PostResult getResult() {
return result;
} }
} }

View File

@ -1,6 +1,7 @@
package eu.kanade.mangafeed.ui.manga.chapter; package eu.kanade.mangafeed.ui.manga.chapter;
import android.os.Bundle; import android.os.Bundle;
import android.util.Pair;
import java.util.List; import java.util.List;
@ -20,7 +21,6 @@ import eu.kanade.mangafeed.event.DownloadChaptersEvent;
import eu.kanade.mangafeed.event.ReaderEvent; import eu.kanade.mangafeed.event.ReaderEvent;
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 eu.kanade.mangafeed.util.PostResult;
import rx.Observable; import rx.Observable;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
@ -119,7 +119,7 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
chaptersSubject.onNext(chapters); chaptersSubject.onNext(chapters);
} }
private Observable<PostResult> getOnlineChaptersObs() { private Observable<Pair<Integer, Integer>> getOnlineChaptersObs() {
return source.pullChaptersFromNetwork(manga.url) return source.pullChaptersFromNetwork(manga.url)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters)) .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters))

View File

@ -16,8 +16,8 @@ import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService;
import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; import eu.kanade.mangafeed.data.mangasync.MangaSyncManager;
import eu.kanade.mangafeed.data.source.SourceManager; import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.data.source.base.Source; import eu.kanade.mangafeed.data.source.base.Source;
import eu.kanade.mangafeed.ui.setting.preference.MangaSyncLoginDialog; import eu.kanade.mangafeed.widget.preference.MangaSyncLoginDialog;
import eu.kanade.mangafeed.ui.setting.preference.SourceLoginDialog; import eu.kanade.mangafeed.widget.preference.SourceLoginDialog;
import rx.Observable; import rx.Observable;
public class SettingsAccountsFragment extends SettingsNestedFragment { public class SettingsAccountsFragment extends SettingsNestedFragment {

View File

@ -8,8 +8,8 @@ import android.view.ViewGroup;
import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.data.preference.PreferencesHelper;
import eu.kanade.mangafeed.data.sync.LibraryUpdateAlarm; import eu.kanade.mangafeed.data.sync.LibraryUpdateAlarm;
import eu.kanade.mangafeed.ui.setting.preference.IntListPreference; import eu.kanade.mangafeed.widget.preference.IntListPreference;
import eu.kanade.mangafeed.ui.setting.preference.LibraryColumnsDialog; import eu.kanade.mangafeed.widget.preference.LibraryColumnsDialog;
public class SettingsGeneralFragment extends SettingsNestedFragment { public class SettingsGeneralFragment extends SettingsNestedFragment {

View File

@ -1,33 +0,0 @@
package eu.kanade.mangafeed.util;
import android.support.annotation.Nullable;
public class PostResult {
@Nullable
private final Integer numberOfRowsUpdated;
@Nullable
private final Integer numberOfRowsInserted;
@Nullable
private final Integer numberOfRowsDeleted;
public PostResult(Integer numberOfRowsUpdated, Integer numberOfRowsInserted, Integer numberOfRowsDeleted) {
this.numberOfRowsUpdated = numberOfRowsUpdated;
this.numberOfRowsInserted = numberOfRowsInserted;
this.numberOfRowsDeleted = numberOfRowsDeleted;
}
public Integer getNumberOfRowsUpdated() {
return numberOfRowsUpdated;
}
public Integer getNumberOfRowsInserted() {
return numberOfRowsInserted;
}
public Integer getNumberOfRowsDeleted() {
return numberOfRowsDeleted;
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.setting.preference; package eu.kanade.mangafeed.widget.preference;
import android.content.Context; import android.content.Context;
import android.preference.ListPreference; import android.preference.ListPreference;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.setting.preference; package eu.kanade.mangafeed.widget.preference;
import android.content.Context; import android.content.Context;
import android.preference.DialogPreference; import android.preference.DialogPreference;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.setting.preference; package eu.kanade.mangafeed.widget.preference;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.setting.preference; package eu.kanade.mangafeed.widget.preference;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.setting.preference; package eu.kanade.mangafeed.widget.preference;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;

View File

@ -5,7 +5,7 @@
android:title="@string/pref_download_directory" android:title="@string/pref_download_directory"
android:key="@string/pref_download_directory_key"/> android:key="@string/pref_download_directory_key"/>
<eu.kanade.mangafeed.ui.setting.preference.IntListPreference <eu.kanade.mangafeed.widget.preference.IntListPreference
android:title="@string/pref_download_slots" android:title="@string/pref_download_slots"
android:key="@string/pref_download_slots_key" android:key="@string/pref_download_slots_key"
android:entries="@array/download_slots" android:entries="@array/download_slots"

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<eu.kanade.mangafeed.ui.setting.preference.LibraryColumnsDialog <eu.kanade.mangafeed.widget.preference.LibraryColumnsDialog
android:key="@string/pref_library_columns_dialog_key" android:key="@string/pref_library_columns_dialog_key"
android:persistent="false" android:persistent="false"
android:title="@string/pref_library_columns"/> android:title="@string/pref_library_columns"/>
<eu.kanade.mangafeed.ui.setting.preference.IntListPreference <eu.kanade.mangafeed.widget.preference.IntListPreference
android:key="@string/pref_library_update_interval_key" android:key="@string/pref_library_update_interval_key"
android:title="@string/pref_library_update_interval" android:title="@string/pref_library_update_interval"
android:entries="@array/library_update_interval" android:entries="@array/library_update_interval"

View File

@ -28,7 +28,7 @@
android:defaultValue="1" android:defaultValue="1"
android:summary="%s"/> android:summary="%s"/>
<eu.kanade.mangafeed.ui.setting.preference.IntListPreference <eu.kanade.mangafeed.widget.preference.IntListPreference
android:title="@string/pref_reader_theme" android:title="@string/pref_reader_theme"
android:key="@string/pref_reader_theme_key" android:key="@string/pref_reader_theme_key"
android:entries="@array/reader_themes" android:entries="@array/reader_themes"
@ -36,7 +36,7 @@
android:defaultValue="0" android:defaultValue="0"
android:summary="%s"/> android:summary="%s"/>
<eu.kanade.mangafeed.ui.setting.preference.IntListPreference <eu.kanade.mangafeed.widget.preference.IntListPreference
android:title="@string/pref_image_decoder" android:title="@string/pref_image_decoder"
android:key="@string/pref_image_decoder_key" android:key="@string/pref_image_decoder_key"
android:entries="@array/image_decoders" android:entries="@array/image_decoders"