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;
import android.content.Context;
import android.util.Pair;
import com.pushtorefresh.storio.Queries;
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.put.PreparedPutCollectionOfObjects;
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.Query;
import com.pushtorefresh.storio.sqlite.queries.RawQuery;
import java.util.Date;
import java.util.List;
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.mangasync.base.MangaSyncService;
import eu.kanade.mangafeed.util.ChapterRecognition;
import eu.kanade.mangafeed.util.PostResult;
import rx.Observable;
public class DatabaseHelper {
@ -246,37 +246,46 @@ public class DatabaseHelper {
}
// Add new chapters or delete if the source deletes them
public Observable<PostResult> insertOrRemoveChapters(Manga manga, List<Chapter> chapters) {
for (Chapter chapter : chapters) {
chapter.manga_id = manga.id;
public Observable<Pair<Integer, Integer>> insertOrRemoveChapters(Manga manga, List<Chapter> sourceChapters) {
List<Chapter> dbChapters = getChapters(manga).executeAsBlocking();
Observable<List<Chapter>> newChapters = Observable.from(sourceChapters)
.filter(c -> !dbChapters.contains(c))
.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();
}
Observable<List<Chapter>> chapterList = Observable.create(subscriber -> {
subscriber.onNext(getChapters(manga).executeAsBlocking());
subscriber.onCompleted();
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) {

View file

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

View file

@ -14,7 +14,6 @@ import org.jsoup.nodes.Element;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
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();
} catch (ParseException e) { /* Ignore */ }
}
chapter.date_fetch = new Date().getTime();
return chapter;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -8,8 +8,8 @@ import android.view.ViewGroup;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.preference.PreferencesHelper;
import eu.kanade.mangafeed.data.sync.LibraryUpdateAlarm;
import eu.kanade.mangafeed.ui.setting.preference.IntListPreference;
import eu.kanade.mangafeed.ui.setting.preference.LibraryColumnsDialog;
import eu.kanade.mangafeed.widget.preference.IntListPreference;
import eu.kanade.mangafeed.widget.preference.LibraryColumnsDialog;
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.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.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.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.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.DialogInterface;

View file

@ -5,7 +5,7 @@
android:title="@string/pref_download_directory"
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:key="@string/pref_download_slots_key"
android:entries="@array/download_slots"

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<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:persistent="false"
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:title="@string/pref_library_update_interval"
android:entries="@array/library_update_interval"

View file

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