mirror of
https://github.com/mihonapp/mihon.git
synced 2024-12-25 02:18:24 +01:00
Use interfaces for database managers, create a source manager
This commit is contained in:
parent
7e3d7cb4c4
commit
67a2e99cc1
@ -10,6 +10,7 @@ import eu.kanade.mangafeed.data.caches.CacheManager;
|
|||||||
import eu.kanade.mangafeed.data.helpers.DatabaseHelper;
|
import eu.kanade.mangafeed.data.helpers.DatabaseHelper;
|
||||||
import eu.kanade.mangafeed.data.helpers.NetworkHelper;
|
import eu.kanade.mangafeed.data.helpers.NetworkHelper;
|
||||||
import eu.kanade.mangafeed.data.helpers.PreferencesHelper;
|
import eu.kanade.mangafeed.data.helpers.PreferencesHelper;
|
||||||
|
import eu.kanade.mangafeed.data.helpers.SourceManager;
|
||||||
import rx.Scheduler;
|
import rx.Scheduler;
|
||||||
import rx.schedulers.Schedulers;
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
@ -49,4 +50,9 @@ public class DataModule {
|
|||||||
return new NetworkHelper();
|
return new NetworkHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
SourceManager provideSourceManager(NetworkHelper networkHelper, CacheManager cacheManager) {
|
||||||
|
return new SourceManager(networkHelper, cacheManager);
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,9 +5,17 @@ import android.content.Context;
|
|||||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
|
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
|
||||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
||||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite;
|
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import eu.kanade.mangafeed.data.managers.ChapterManager;
|
import eu.kanade.mangafeed.data.managers.ChapterManager;
|
||||||
|
import eu.kanade.mangafeed.data.managers.ChapterManagerImpl;
|
||||||
import eu.kanade.mangafeed.data.managers.MangaManager;
|
import eu.kanade.mangafeed.data.managers.MangaManager;
|
||||||
|
import eu.kanade.mangafeed.data.managers.MangaManagerImpl;
|
||||||
import eu.kanade.mangafeed.data.models.Chapter;
|
import eu.kanade.mangafeed.data.models.Chapter;
|
||||||
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteDeleteResolver;
|
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteDeleteResolver;
|
||||||
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteGetResolver;
|
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteGetResolver;
|
||||||
@ -16,16 +24,17 @@ import eu.kanade.mangafeed.data.models.Manga;
|
|||||||
import eu.kanade.mangafeed.data.models.MangaStorIOSQLiteDeleteResolver;
|
import eu.kanade.mangafeed.data.models.MangaStorIOSQLiteDeleteResolver;
|
||||||
import eu.kanade.mangafeed.data.models.MangaStorIOSQLitePutResolver;
|
import eu.kanade.mangafeed.data.models.MangaStorIOSQLitePutResolver;
|
||||||
import eu.kanade.mangafeed.data.resolvers.MangaWithUnreadGetResolver;
|
import eu.kanade.mangafeed.data.resolvers.MangaWithUnreadGetResolver;
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
public class DatabaseHelper {
|
public class DatabaseHelper implements MangaManager, ChapterManager {
|
||||||
|
|
||||||
private StorIOSQLite db;
|
private StorIOSQLite mDb;
|
||||||
public MangaManager manga;
|
private MangaManagerImpl mMangaManager;
|
||||||
public ChapterManager chapter;
|
private ChapterManagerImpl mChapterManager;
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
public DatabaseHelper(Context context) {
|
||||||
|
|
||||||
db = DefaultStorIOSQLite.builder()
|
mDb = DefaultStorIOSQLite.builder()
|
||||||
.sqliteOpenHelper(new DbOpenHelper(context))
|
.sqliteOpenHelper(new DbOpenHelper(context))
|
||||||
.addTypeMapping(Manga.class, SQLiteTypeMapping.<Manga>builder()
|
.addTypeMapping(Manga.class, SQLiteTypeMapping.<Manga>builder()
|
||||||
.putResolver(new MangaStorIOSQLitePutResolver())
|
.putResolver(new MangaStorIOSQLitePutResolver())
|
||||||
@ -39,8 +48,67 @@ public class DatabaseHelper {
|
|||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
manga = new MangaManager(db);
|
mMangaManager = new MangaManagerImpl(mDb);
|
||||||
chapter = new ChapterManager(db);
|
mChapterManager = new ChapterManagerImpl(mDb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<List<Chapter>> getChapters(Manga manga) {
|
||||||
|
return mChapterManager.getChapters(manga);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResult> insertChapter(Chapter chapter) {
|
||||||
|
return mChapterManager.insertChapter(chapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters) {
|
||||||
|
return mChapterManager.insertChapters(chapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters) {
|
||||||
|
return mChapterManager.insertOrRemoveChapters(manga, chapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResult> deleteChapter(Chapter chapter) {
|
||||||
|
return mChapterManager.deleteChapter(chapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResults<Chapter>> deleteChapters(List<Chapter> chapters) {
|
||||||
|
return mChapterManager.deleteChapters(chapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<List<Manga>> getMangas() {
|
||||||
|
return mMangaManager.getMangas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<List<Manga>> getMangasWithUnread() {
|
||||||
|
return mMangaManager.getMangasWithUnread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResult> insertManga(Manga manga) {
|
||||||
|
return mMangaManager.insertManga(manga);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResults<Manga>> insertMangas(List<Manga> mangas) {
|
||||||
|
return mMangaManager.insertMangas(mangas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResult> deleteManga(Manga manga) {
|
||||||
|
return mMangaManager.deleteManga(manga);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas) {
|
||||||
|
return mMangaManager.deleteMangas(mangas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package eu.kanade.mangafeed.data.helpers;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import eu.kanade.mangafeed.data.caches.CacheManager;
|
||||||
|
import eu.kanade.mangafeed.sources.Batoto;
|
||||||
|
import eu.kanade.mangafeed.sources.Source;
|
||||||
|
|
||||||
|
public class SourceManager {
|
||||||
|
|
||||||
|
public static final int BATOTO = 1;
|
||||||
|
|
||||||
|
private HashMap<Integer, Source> mSourcesMap;
|
||||||
|
private NetworkHelper mNetworkHelper;
|
||||||
|
private CacheManager mCacheManager;
|
||||||
|
|
||||||
|
public SourceManager(NetworkHelper networkHelper, CacheManager cacheManager) {
|
||||||
|
mSourcesMap = new HashMap<>();
|
||||||
|
mNetworkHelper = networkHelper;
|
||||||
|
mCacheManager = cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Source get(int sourceKey) {
|
||||||
|
if (!mSourcesMap.containsKey(sourceKey)) {
|
||||||
|
mSourcesMap.put(sourceKey, createSource(sourceKey));
|
||||||
|
}
|
||||||
|
return mSourcesMap.get(sourceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Source createSource(int sourceKey) {
|
||||||
|
switch (sourceKey) {
|
||||||
|
case BATOTO:
|
||||||
|
return new Batoto(mNetworkHelper, mCacheManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,107 +1,28 @@
|
|||||||
package eu.kanade.mangafeed.data.managers;
|
package eu.kanade.mangafeed.data.managers;
|
||||||
|
|
||||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
|
||||||
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
||||||
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
||||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects;
|
|
||||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
||||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
||||||
import com.pushtorefresh.storio.sqlite.queries.Query;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import eu.kanade.mangafeed.data.models.Chapter;
|
import eu.kanade.mangafeed.data.models.Chapter;
|
||||||
import eu.kanade.mangafeed.data.models.Manga;
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
import eu.kanade.mangafeed.data.tables.ChaptersTable;
|
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
|
||||||
public class ChapterManager extends BaseManager {
|
public interface ChapterManager {
|
||||||
|
|
||||||
public ChapterManager(StorIOSQLite db) {
|
Observable<List<Chapter>> getChapters(Manga manga);
|
||||||
super(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PreparedGetListOfObjects<Chapter> prepareGet(Manga manga) {
|
Observable<PutResult> insertChapter(Chapter chapter);
|
||||||
return db.get()
|
|
||||||
.listOfObjects(Chapter.class)
|
|
||||||
.withQuery(Query.builder()
|
|
||||||
.table(ChaptersTable.TABLE)
|
|
||||||
.where(ChaptersTable.COLUMN_MANGA_ID + "=?")
|
|
||||||
.whereArgs(manga.id)
|
|
||||||
.build())
|
|
||||||
.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<List<Chapter>> get(Manga manga) {
|
Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters);
|
||||||
return prepareGet(manga).createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<PutResult> insert(Chapter chapter) {
|
Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters);
|
||||||
return db.put()
|
|
||||||
.object(chapter)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<PutResults<Chapter>> insert(List<Chapter> chapters) {
|
Observable<DeleteResult> deleteChapter(Chapter chapter);
|
||||||
return db.put()
|
|
||||||
.objects(chapters)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new chapters or delete if the source deletes them
|
Observable<DeleteResults<Chapter>> deleteChapters(List<Chapter> chapters);
|
||||||
public Observable insertOrRemove(Manga manga, List<Chapter> chapters) {
|
|
||||||
// I don't know a better approach
|
|
||||||
// TODO Fix this method
|
|
||||||
return Observable.create(subscriber -> {
|
|
||||||
List<Chapter> dbChapters = prepareGet(manga).executeAsBlocking();
|
|
||||||
|
|
||||||
Observable<List<Chapter>> newChaptersObs =
|
|
||||||
Observable.from(chapters)
|
|
||||||
.filter(c -> !dbChapters.contains(c))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
Observable<List<Chapter>> deletedChaptersObs =
|
|
||||||
Observable.from(dbChapters)
|
|
||||||
.filter(c -> !chapters.contains(c))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
Observable.zip(newChaptersObs, deletedChaptersObs,
|
|
||||||
(newChapters, deletedChapters) -> {
|
|
||||||
insert(newChapters).subscribe();
|
|
||||||
delete(deletedChapters).subscribe();
|
|
||||||
subscriber.onCompleted();
|
|
||||||
return null;
|
|
||||||
}).subscribe();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createDummyChapters() {
|
|
||||||
Chapter c;
|
|
||||||
|
|
||||||
for (int i = 1; i < 100; i++) {
|
|
||||||
c = new Chapter();
|
|
||||||
c.manga_id = 1L;
|
|
||||||
c.name = "Chapter " + i;
|
|
||||||
c.url = "http://example.com/1";
|
|
||||||
insert(c).subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<DeleteResults<Chapter>> delete(List<Chapter> chapters) {
|
|
||||||
return db.delete()
|
|
||||||
.objects(chapters)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<DeleteResult> delete(Chapter chapter) {
|
|
||||||
return db.delete()
|
|
||||||
.object(chapter)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
package eu.kanade.mangafeed.data.managers;
|
||||||
|
|
||||||
|
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
||||||
|
import com.pushtorefresh.storio.sqlite.queries.Query;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.kanade.mangafeed.data.models.Chapter;
|
||||||
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
|
import eu.kanade.mangafeed.data.tables.ChaptersTable;
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
|
public class ChapterManagerImpl extends BaseManager implements ChapterManager {
|
||||||
|
|
||||||
|
public ChapterManagerImpl(StorIOSQLite db) {
|
||||||
|
super(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PreparedGetListOfObjects<Chapter> prepareGet(Manga manga) {
|
||||||
|
return db.get()
|
||||||
|
.listOfObjects(Chapter.class)
|
||||||
|
.withQuery(Query.builder()
|
||||||
|
.table(ChaptersTable.TABLE)
|
||||||
|
.where(ChaptersTable.COLUMN_MANGA_ID + "=?")
|
||||||
|
.whereArgs(manga.id)
|
||||||
|
.build())
|
||||||
|
.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<List<Chapter>> getChapters(Manga manga) {
|
||||||
|
return prepareGet(manga).createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResult> insertChapter(Chapter chapter) {
|
||||||
|
return db.put()
|
||||||
|
.object(chapter)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters) {
|
||||||
|
return db.put()
|
||||||
|
.objects(chapters)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new chapters or delete if the source deletes them
|
||||||
|
@Override
|
||||||
|
public Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters) {
|
||||||
|
// I don't know a better approach
|
||||||
|
// TODO Fix this method
|
||||||
|
return Observable.create(subscriber -> {
|
||||||
|
List<Chapter> dbChapters = prepareGet(manga).executeAsBlocking();
|
||||||
|
|
||||||
|
Observable<List<Chapter>> newChaptersObs =
|
||||||
|
Observable.from(chapters)
|
||||||
|
.filter(c -> !dbChapters.contains(c))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Observable<List<Chapter>> deletedChaptersObs =
|
||||||
|
Observable.from(dbChapters)
|
||||||
|
.filter(c -> !chapters.contains(c))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Observable.zip(newChaptersObs, deletedChaptersObs,
|
||||||
|
(newChapters, deletedChapters) -> {
|
||||||
|
insertChapters(newChapters).subscribe();
|
||||||
|
deleteChapters(deletedChapters).subscribe();
|
||||||
|
subscriber.onCompleted();
|
||||||
|
return null;
|
||||||
|
}).subscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResult> deleteChapter(Chapter chapter) {
|
||||||
|
return db.delete()
|
||||||
|
.object(chapter)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<DeleteResults<Chapter>> deleteChapters(List<Chapter> chapters) {
|
||||||
|
return db.delete()
|
||||||
|
.objects(chapters)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,97 +1,27 @@
|
|||||||
package eu.kanade.mangafeed.data.managers;
|
package eu.kanade.mangafeed.data.managers;
|
||||||
|
|
||||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
|
||||||
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
||||||
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
||||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
||||||
import com.pushtorefresh.storio.sqlite.queries.Query;
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
||||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import eu.kanade.mangafeed.data.models.Manga;
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
import eu.kanade.mangafeed.data.tables.ChaptersTable;
|
|
||||||
import eu.kanade.mangafeed.data.tables.MangasTable;
|
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
|
||||||
public class MangaManager extends BaseManager {
|
public interface MangaManager {
|
||||||
|
|
||||||
public MangaManager(StorIOSQLite db) {
|
Observable<List<Manga>> getMangas();
|
||||||
super(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String mangasWithUnreadQuery = String.format(
|
Observable<List<Manga>> getMangasWithUnread();
|
||||||
"SELECT %1$s.*, COUNT(C.%4$s) AS %5$s FROM %1$s LEFT JOIN " +
|
|
||||||
"(SELECT %4$s FROM %2$s WHERE %6$s = 0) AS C ON %3$s = C.%4$s " +
|
|
||||||
"GROUP BY %3$s",
|
|
||||||
MangasTable.TABLE,
|
|
||||||
ChaptersTable.TABLE,
|
|
||||||
MangasTable.TABLE + "." + MangasTable.COLUMN_ID,
|
|
||||||
ChaptersTable.COLUMN_MANGA_ID,
|
|
||||||
MangasTable.COLUMN_UNREAD,
|
|
||||||
ChaptersTable.COLUMN_READ
|
|
||||||
);
|
|
||||||
|
|
||||||
public Observable<List<Manga>> get() {
|
Observable<PutResult> insertManga(Manga manga);
|
||||||
return db.get()
|
|
||||||
.listOfObjects(Manga.class)
|
|
||||||
.withQuery(Query.builder()
|
|
||||||
.table(MangasTable.TABLE)
|
|
||||||
.build())
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<List<Manga>> getWithUnread() {
|
Observable<PutResults<Manga>> insertMangas(List<Manga> mangas);
|
||||||
return db.get()
|
|
||||||
.listOfObjects(Manga.class)
|
|
||||||
.withQuery(RawQuery.builder()
|
|
||||||
.query(mangasWithUnreadQuery)
|
|
||||||
.observesTables(MangasTable.TABLE, ChaptersTable.TABLE)
|
|
||||||
.build())
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<PutResult> insert(Manga manga) {
|
Observable<DeleteResult> deleteManga(Manga manga);
|
||||||
return db.put()
|
|
||||||
.object(manga)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createDummyManga() {
|
Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas);
|
||||||
insert(createDummyManga("One Piece")).subscribe();
|
|
||||||
insert(createDummyManga("Übel Blatt")).subscribe();
|
|
||||||
insert(createDummyManga("Berserk")).subscribe();
|
|
||||||
insert(createDummyManga("Horimiya")).subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Manga createDummyManga(String title) {
|
|
||||||
Manga m = new Manga();
|
|
||||||
m.title = title;
|
|
||||||
m.url="http://example.com";
|
|
||||||
m.artist="Eiichiro Oda";
|
|
||||||
m.author="Eiichiro Oda";
|
|
||||||
m.description="...";
|
|
||||||
m.genre="Action, Drama";
|
|
||||||
m.status="Ongoing";
|
|
||||||
m.thumbnail_url="http://example.com/pic.png";
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<DeleteResult> delete(Manga manga) {
|
|
||||||
return db.delete()
|
|
||||||
.object(manga)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<DeleteResults<Manga>> delete(List<Manga> mangas) {
|
|
||||||
return db.delete()
|
|
||||||
.objects(mangas)
|
|
||||||
.prepare()
|
|
||||||
.createObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package eu.kanade.mangafeed.data.managers;
|
||||||
|
|
||||||
|
import com.pushtorefresh.storio.sqlite.StorIOSQLite;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
|
||||||
|
import com.pushtorefresh.storio.sqlite.queries.Query;
|
||||||
|
import com.pushtorefresh.storio.sqlite.queries.RawQuery;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
|
import eu.kanade.mangafeed.data.tables.ChaptersTable;
|
||||||
|
import eu.kanade.mangafeed.data.tables.MangasTable;
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
|
public class MangaManagerImpl extends BaseManager implements MangaManager {
|
||||||
|
|
||||||
|
public MangaManagerImpl(StorIOSQLite db) {
|
||||||
|
super(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String mangasWithUnreadQuery = String.format(
|
||||||
|
"SELECT %1$s.*, COUNT(C.%4$s) AS %5$s FROM %1$s LEFT JOIN " +
|
||||||
|
"(SELECT %4$s FROM %2$s WHERE %6$s = 0) AS C ON %3$s = C.%4$s " +
|
||||||
|
"GROUP BY %3$s",
|
||||||
|
MangasTable.TABLE,
|
||||||
|
ChaptersTable.TABLE,
|
||||||
|
MangasTable.TABLE + "." + MangasTable.COLUMN_ID,
|
||||||
|
ChaptersTable.COLUMN_MANGA_ID,
|
||||||
|
MangasTable.COLUMN_UNREAD,
|
||||||
|
ChaptersTable.COLUMN_READ
|
||||||
|
);
|
||||||
|
|
||||||
|
public Observable<List<Manga>> getMangas() {
|
||||||
|
return db.get()
|
||||||
|
.listOfObjects(Manga.class)
|
||||||
|
.withQuery(Query.builder()
|
||||||
|
.table(MangasTable.TABLE)
|
||||||
|
.build())
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<List<Manga>> getMangasWithUnread() {
|
||||||
|
return db.get()
|
||||||
|
.listOfObjects(Manga.class)
|
||||||
|
.withQuery(RawQuery.builder()
|
||||||
|
.query(mangasWithUnreadQuery)
|
||||||
|
.observesTables(MangasTable.TABLE, ChaptersTable.TABLE)
|
||||||
|
.build())
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<PutResult> insertManga(Manga manga) {
|
||||||
|
return db.put()
|
||||||
|
.object(manga)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<PutResults<Manga>> insertMangas(List<Manga> mangas) {
|
||||||
|
return db.put()
|
||||||
|
.objects(mangas)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<DeleteResult> deleteManga(Manga manga) {
|
||||||
|
return db.delete()
|
||||||
|
.object(manga)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas) {
|
||||||
|
return db.delete()
|
||||||
|
.objects(mangas)
|
||||||
|
.prepare()
|
||||||
|
.createObservable();
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,8 @@ public class ChaptersTable {
|
|||||||
+ COLUMN_DATE_UPLOAD + " LONG NOT NULL, "
|
+ COLUMN_DATE_UPLOAD + " LONG NOT NULL, "
|
||||||
+ "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangasTable.TABLE + "(" + MangasTable.COLUMN_ID + ") "
|
+ "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangasTable.TABLE + "(" + MangasTable.COLUMN_ID + ") "
|
||||||
+ "ON DELETE CASCADE"
|
+ "ON DELETE CASCADE"
|
||||||
+ ");";
|
+ ");"
|
||||||
|
+ "CREATE INDEX " + TABLE + "_" + COLUMN_MANGA_ID + "_index ON " + TABLE + "(" + COLUMN_MANGA_ID + ");";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import eu.kanade.mangafeed.data.helpers.PreferencesHelper;
|
|||||||
import eu.kanade.mangafeed.data.models.Manga;
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
import eu.kanade.mangafeed.ui.activity.MangaDetailActivity;
|
import eu.kanade.mangafeed.ui.activity.MangaDetailActivity;
|
||||||
import eu.kanade.mangafeed.ui.adapter.LibraryAdapter;
|
import eu.kanade.mangafeed.ui.adapter.LibraryAdapter;
|
||||||
|
import eu.kanade.mangafeed.util.DummyDataUtil;
|
||||||
import eu.kanade.mangafeed.view.LibraryView;
|
import eu.kanade.mangafeed.view.LibraryView;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
import rx.schedulers.Schedulers;
|
import rx.schedulers.Schedulers;
|
||||||
@ -32,8 +33,8 @@ public class LibraryPresenter extends BasePresenter {
|
|||||||
|
|
||||||
//TODO remove, only for testing
|
//TODO remove, only for testing
|
||||||
if (prefs.isFirstRun()) {
|
if (prefs.isFirstRun()) {
|
||||||
db.manga.createDummyManga();
|
db.insertMangas(DummyDataUtil.createDummyManga()).toBlocking().single();
|
||||||
db.chapter.createDummyChapters();
|
db.insertChapters(DummyDataUtil.createDummyChapters()).subscribe();
|
||||||
prefs.setNotFirstRun();
|
prefs.setNotFirstRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +53,11 @@ public class LibraryPresenter extends BasePresenter {
|
|||||||
view.setAdapter(adapter);
|
view.setAdapter(adapter);
|
||||||
view.setMangaClickListener();
|
view.setMangaClickListener();
|
||||||
|
|
||||||
subscriptions.add(db.manga.getWithUnread()
|
subscriptions.add(db.getMangasWithUnread()
|
||||||
.observeOn(mainThread())
|
.observeOn(mainThread())
|
||||||
.subscribe(adapter::setNewItems)
|
.subscribe(adapter::setNewItems)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onQueryTextChange(String query) {
|
public void onQueryTextChange(String query) {
|
||||||
@ -68,7 +70,7 @@ public class LibraryPresenter extends BasePresenter {
|
|||||||
.map(checkedItems::keyAt)
|
.map(checkedItems::keyAt)
|
||||||
.map(adapter::getItem)
|
.map(adapter::getItem)
|
||||||
.toList()
|
.toList()
|
||||||
.flatMap(db.manga::delete)
|
.flatMap(db::deleteMangas)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public class MangaDetailPresenter extends BasePresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initializeChapters(Manga manga) {
|
public void initializeChapters(Manga manga) {
|
||||||
db.chapter.get(manga)
|
db.getChapters(manga)
|
||||||
.subscribe(view::setChapters);
|
.subscribe(view::setChapters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.mangafeed.sources;
|
package eu.kanade.mangafeed.sources;
|
||||||
|
|
||||||
import com.squareup.okhttp.Headers;
|
import com.squareup.okhttp.Headers;
|
||||||
import com.squareup.okhttp.Response;
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
@ -18,18 +17,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
import eu.kanade.mangafeed.data.caches.CacheManager;
|
import eu.kanade.mangafeed.data.caches.CacheManager;
|
||||||
import eu.kanade.mangafeed.data.helpers.NetworkHelper;
|
import eu.kanade.mangafeed.data.helpers.NetworkHelper;
|
||||||
|
import eu.kanade.mangafeed.data.helpers.SourceManager;
|
||||||
import eu.kanade.mangafeed.data.models.Chapter;
|
import eu.kanade.mangafeed.data.models.Chapter;
|
||||||
import eu.kanade.mangafeed.data.models.Manga;
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
import rx.functions.Func1;
|
|
||||||
import rx.schedulers.Schedulers;
|
import rx.schedulers.Schedulers;
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class Batoto {
|
public class Batoto extends Source {
|
||||||
|
|
||||||
public static final String NAME = "Batoto (EN)";
|
public static final String NAME = "Batoto (EN)";
|
||||||
public static final String BASE_URL = "www.bato.to";
|
public static final String BASE_URL = "www.bato.to";
|
||||||
public static final String INITIAL_UPDATE_URL = "http://bato.to/search_ajax?order_cond=update&order=desc&p=1";
|
public static final String INITIAL_UPDATE_URL = "http://bato.to/search_ajax?order_cond=views&order=desc&p=1";
|
||||||
|
|
||||||
private static final Headers REQUEST_HEADERS = constructRequestHeaders();
|
private static final Headers REQUEST_HEADERS = constructRequestHeaders();
|
||||||
private static Headers constructRequestHeaders() {
|
private static Headers constructRequestHeaders() {
|
||||||
@ -105,38 +103,32 @@ public class Batoto {
|
|||||||
return Observable.just(genres);
|
return Observable.just(genres);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
public String getUrlFromPageNumber(int page) {
|
||||||
public Observable<UpdatePageMarker> pullLatestUpdatesFromNetwork(final UpdatePageMarker newUpdate) {
|
if (page == 1)
|
||||||
return mNetworkService
|
return INITIAL_UPDATE_URL;
|
||||||
.getResponse(newUpdate.getNextPageUrl(), NetworkModule.NULL_CACHE_CONTROL, REQUEST_HEADERS)
|
|
||||||
.flatMap(new Func1<Response, Observable<String>>() {
|
return INITIAL_UPDATE_URL.substring(0, INITIAL_UPDATE_URL.length() - 1) + page;
|
||||||
@Override
|
|
||||||
public Observable<String> call(Response response) {
|
|
||||||
return mNetworkService.mapResponseToString(response);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.flatMap(new Func1<String, Observable<UpdatePageMarker>>() {
|
|
||||||
@Override
|
|
||||||
public Observable<UpdatePageMarker> call(String unparsedHtml) {
|
|
||||||
return Observable.just(parseHtmlToLatestUpdates(newUpdate.getNextPageUrl(), unparsedHtml));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpdatePageMarker parseHtmlToLatestUpdates(String requestUrl, String unparsedHtml) {
|
public Observable<List<Manga>> pullPopularMangasFromNetwork(int page) {
|
||||||
|
String url = getUrlFromPageNumber(page);
|
||||||
|
return mNetworkService
|
||||||
|
.getStringResponse(url, mNetworkService.NULL_CACHE_CONTROL, REQUEST_HEADERS)
|
||||||
|
.flatMap(response -> Observable.just(parseHtmlToLatestUpdates(response)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Manga> parseHtmlToLatestUpdates(String unparsedHtml) {
|
||||||
Document parsedDocument = Jsoup.parse(unparsedHtml);
|
Document parsedDocument = Jsoup.parse(unparsedHtml);
|
||||||
|
|
||||||
List<Manga> updatedMangaList = scrapeUpdateMangasFromParsedDocument(parsedDocument);
|
List<Manga> updatedMangaList = scrapeUpdateMangasFromParsedDocument(parsedDocument);
|
||||||
updateLibraryInDatabase(updatedMangaList);
|
//updateLibraryInDatabase(updatedMangaList);
|
||||||
|
|
||||||
String nextPageUrl = findNextUrlFromParsedDocument(requestUrl, unparsedHtml);
|
return updatedMangaList;
|
||||||
int lastMangaPostion = updatedMangaList.size();
|
|
||||||
|
|
||||||
return new UpdatePageMarker(nextPageUrl, lastMangaPostion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<Manga> scrapeUpdateMangasFromParsedDocument(Document parsedDocument) {
|
private List<Manga> scrapeUpdateMangasFromParsedDocument(Document parsedDocument) {
|
||||||
List<Manga> updatedMangaList = new ArrayList<Manga>();
|
List<Manga> updatedMangaList = new ArrayList<>();
|
||||||
|
|
||||||
Elements updatedHtmlBlocks = parsedDocument.select("tr:not([id]):not([class])");
|
Elements updatedHtmlBlocks = parsedDocument.select("tr:not([id]):not([class])");
|
||||||
for (Element currentHtmlBlock : updatedHtmlBlocks) {
|
for (Element currentHtmlBlock : updatedHtmlBlocks) {
|
||||||
@ -149,29 +141,27 @@ public class Batoto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Manga constructMangaFromHtmlBlock(Element htmlBlock) {
|
private Manga constructMangaFromHtmlBlock(Element htmlBlock) {
|
||||||
Manga mangaFromHtmlBlock = DefaultFactory.Manga.constructDefault();
|
Manga mangaFromHtmlBlock = new Manga();
|
||||||
mangaFromHtmlBlock.setSource(NAME);
|
|
||||||
|
|
||||||
Element urlElement = htmlBlock.select("a[href^=http://bato.to]").first();
|
Element urlElement = htmlBlock.select("a[href^=http://bato.to]").first();
|
||||||
Element nameElement = urlElement;
|
Element nameElement = urlElement;
|
||||||
Element updateElement = htmlBlock.select("td").get(5);
|
Element updateElement = htmlBlock.select("td").get(5);
|
||||||
|
|
||||||
|
mangaFromHtmlBlock.source = SourceManager.BATOTO;
|
||||||
|
|
||||||
if (urlElement != null) {
|
if (urlElement != null) {
|
||||||
String fieldUrl = urlElement.attr("href");
|
String fieldUrl = urlElement.attr("href");
|
||||||
mangaFromHtmlBlock.setUrl(fieldUrl);
|
mangaFromHtmlBlock.url = fieldUrl;
|
||||||
}
|
}
|
||||||
if (nameElement != null) {
|
if (nameElement != null) {
|
||||||
String fieldName = nameElement.text().trim();
|
String fieldName = nameElement.text().trim();
|
||||||
mangaFromHtmlBlock.setName(fieldName);
|
mangaFromHtmlBlock.title = fieldName;
|
||||||
}
|
}
|
||||||
if (updateElement != null) {
|
if (updateElement != null) {
|
||||||
long fieldUpdate = parseUpdateFromElement(updateElement);
|
long fieldUpdate = parseUpdateFromElement(updateElement);
|
||||||
mangaFromHtmlBlock.setUpdated(fieldUpdate);
|
mangaFromHtmlBlock.last_update = fieldUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateCount = 1;
|
|
||||||
mangaFromHtmlBlock.setUpdateCount(updateCount);
|
|
||||||
|
|
||||||
return mangaFromHtmlBlock;
|
return mangaFromHtmlBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,9 +176,11 @@ public class Batoto {
|
|||||||
// Do Nothing.
|
// Do Nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefaultFactory.Manga.DEFAULT_UPDATED;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
private void updateLibraryInDatabase(List<Manga> mangaList) {
|
private void updateLibraryInDatabase(List<Manga> mangaList) {
|
||||||
mQueryManager.beginLibraryTransaction();
|
mQueryManager.beginLibraryTransaction();
|
||||||
try {
|
try {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package eu.kanade.mangafeed.sources;
|
||||||
|
|
||||||
|
|
||||||
|
public class Source {
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package eu.kanade.mangafeed.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.kanade.mangafeed.data.models.Chapter;
|
||||||
|
import eu.kanade.mangafeed.data.models.Manga;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by len on 8/10/15.
|
||||||
|
*/
|
||||||
|
public class DummyDataUtil {
|
||||||
|
|
||||||
|
public static List<Manga> createDummyManga() {
|
||||||
|
ArrayList<Manga> mangas = new ArrayList<>();
|
||||||
|
mangas.add(createDummyManga("One Piece"));
|
||||||
|
mangas.add(createDummyManga("Berserk"));
|
||||||
|
mangas.add(createDummyManga("Horimiya"));
|
||||||
|
mangas.add(createDummyManga("Übel Blatt"));
|
||||||
|
|
||||||
|
return mangas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Manga createDummyManga(String title) {
|
||||||
|
Manga m = new Manga();
|
||||||
|
m.title = title;
|
||||||
|
m.url="http://example.com";
|
||||||
|
m.artist="Eiichiro Oda";
|
||||||
|
m.author="Eiichiro Oda";
|
||||||
|
m.description="...";
|
||||||
|
m.genre="Action, Drama";
|
||||||
|
m.status="Ongoing";
|
||||||
|
m.thumbnail_url="http://example.com/pic.png";
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Chapter> createDummyChapters() {
|
||||||
|
List<Chapter> chapters = new ArrayList<>();
|
||||||
|
Chapter c;
|
||||||
|
|
||||||
|
for (int i = 1; i < 50; i++) {
|
||||||
|
c = new Chapter();
|
||||||
|
c.manga_id = 1L;
|
||||||
|
c.name = "Chapter " + i;
|
||||||
|
c.url = "http://example.com/1";
|
||||||
|
chapters.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user