mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Use interfaces for database managers, create a source manager
This commit is contained in:
		| @@ -10,6 +10,7 @@ import eu.kanade.mangafeed.data.caches.CacheManager; | ||||
| import eu.kanade.mangafeed.data.helpers.DatabaseHelper; | ||||
| import eu.kanade.mangafeed.data.helpers.NetworkHelper; | ||||
| import eu.kanade.mangafeed.data.helpers.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.data.helpers.SourceManager; | ||||
| import rx.Scheduler; | ||||
| import rx.schedulers.Schedulers; | ||||
|  | ||||
| @@ -49,4 +50,9 @@ public class DataModule { | ||||
|         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.StorIOSQLite; | ||||
| 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.ChapterManagerImpl; | ||||
| 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.ChapterStorIOSQLiteDeleteResolver; | ||||
| 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.MangaStorIOSQLitePutResolver; | ||||
| import eu.kanade.mangafeed.data.resolvers.MangaWithUnreadGetResolver; | ||||
| import rx.Observable; | ||||
|  | ||||
| public class DatabaseHelper { | ||||
| public class DatabaseHelper implements MangaManager, ChapterManager { | ||||
|  | ||||
|     private StorIOSQLite db; | ||||
|     public MangaManager manga; | ||||
|     public ChapterManager chapter; | ||||
|     private StorIOSQLite mDb; | ||||
|     private MangaManagerImpl mMangaManager; | ||||
|     private ChapterManagerImpl mChapterManager; | ||||
|  | ||||
|     public DatabaseHelper(Context context) { | ||||
|  | ||||
|         db = DefaultStorIOSQLite.builder() | ||||
|         mDb = DefaultStorIOSQLite.builder() | ||||
|                 .sqliteOpenHelper(new DbOpenHelper(context)) | ||||
|                 .addTypeMapping(Manga.class, SQLiteTypeMapping.<Manga>builder() | ||||
|                         .putResolver(new MangaStorIOSQLitePutResolver()) | ||||
| @@ -39,8 +48,67 @@ public class DatabaseHelper { | ||||
|                         .build()) | ||||
|                 .build(); | ||||
|  | ||||
|         manga = new MangaManager(db); | ||||
|         chapter = new ChapterManager(db); | ||||
|         mMangaManager = new MangaManagerImpl(mDb); | ||||
|         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; | ||||
|  | ||||
| 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.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 ChapterManager extends BaseManager { | ||||
| public interface ChapterManager { | ||||
|  | ||||
|     public ChapterManager(StorIOSQLite db) { | ||||
|         super(db); | ||||
|     } | ||||
|     Observable<List<Chapter>> getChapters(Manga manga); | ||||
|  | ||||
|     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(); | ||||
|     } | ||||
|     Observable<PutResult> insertChapter(Chapter chapter); | ||||
|  | ||||
|     public Observable<List<Chapter>> get(Manga manga) { | ||||
|         return prepareGet(manga).createObservable(); | ||||
|     } | ||||
|     Observable<PutResults<Chapter>> insertChapters(List<Chapter> chapters); | ||||
|  | ||||
|     public Observable<PutResult> insert(Chapter chapter) { | ||||
|         return db.put() | ||||
|                 .object(chapter) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|     Observable insertOrRemoveChapters(Manga manga, List<Chapter> chapters); | ||||
|  | ||||
|     public Observable<PutResults<Chapter>> insert(List<Chapter> chapters) { | ||||
|         return db.put() | ||||
|                 .objects(chapters) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|     Observable<DeleteResult> deleteChapter(Chapter chapter); | ||||
|  | ||||
|     // Add new chapters or delete if the source deletes them | ||||
|     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<DeleteResults<Chapter>> deleteChapters(List<Chapter> chapters); | ||||
|  | ||||
|             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; | ||||
|  | ||||
| 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.queries.Query; | ||||
| import com.pushtorefresh.storio.sqlite.queries.RawQuery; | ||||
| import com.pushtorefresh.storio.sqlite.operations.put.PutResults; | ||||
|  | ||||
| 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 MangaManager extends BaseManager { | ||||
| public interface MangaManager { | ||||
|  | ||||
|     public MangaManager(StorIOSQLite db) { | ||||
|         super(db); | ||||
|     } | ||||
|     Observable<List<Manga>> getMangas(); | ||||
|  | ||||
|     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 | ||||
|     ); | ||||
|     Observable<List<Manga>> getMangasWithUnread(); | ||||
|  | ||||
|     public Observable<List<Manga>> get() { | ||||
|         return db.get() | ||||
|                 .listOfObjects(Manga.class) | ||||
|                 .withQuery(Query.builder() | ||||
|                         .table(MangasTable.TABLE) | ||||
|                         .build()) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|     Observable<PutResult> insertManga(Manga manga); | ||||
|  | ||||
|     public Observable<List<Manga>> getWithUnread() { | ||||
|         return db.get() | ||||
|                 .listOfObjects(Manga.class) | ||||
|                 .withQuery(RawQuery.builder() | ||||
|                         .query(mangasWithUnreadQuery) | ||||
|                         .observesTables(MangasTable.TABLE, ChaptersTable.TABLE) | ||||
|                         .build()) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|     Observable<PutResults<Manga>> insertMangas(List<Manga> mangas); | ||||
|  | ||||
|     public Observable<PutResult> insert(Manga manga) { | ||||
|         return db.put() | ||||
|                 .object(manga) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|     Observable<DeleteResult> deleteManga(Manga manga); | ||||
|  | ||||
|     public void createDummyManga() { | ||||
|         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(); | ||||
|     } | ||||
|     Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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, " | ||||
| 				+ "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangasTable.TABLE + "(" + MangasTable.COLUMN_ID + ") " | ||||
| 				+ "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.ui.activity.MangaDetailActivity; | ||||
| import eu.kanade.mangafeed.ui.adapter.LibraryAdapter; | ||||
| import eu.kanade.mangafeed.util.DummyDataUtil; | ||||
| import eu.kanade.mangafeed.view.LibraryView; | ||||
| import rx.Observable; | ||||
| import rx.schedulers.Schedulers; | ||||
| @@ -32,8 +33,8 @@ public class LibraryPresenter extends BasePresenter { | ||||
|  | ||||
|         //TODO remove, only for testing | ||||
|         if (prefs.isFirstRun()) { | ||||
|             db.manga.createDummyManga(); | ||||
|             db.chapter.createDummyChapters(); | ||||
|             db.insertMangas(DummyDataUtil.createDummyManga()).toBlocking().single(); | ||||
|             db.insertChapters(DummyDataUtil.createDummyChapters()).subscribe(); | ||||
|             prefs.setNotFirstRun(); | ||||
|         } | ||||
|  | ||||
| @@ -52,10 +53,11 @@ public class LibraryPresenter extends BasePresenter { | ||||
|         view.setAdapter(adapter); | ||||
|         view.setMangaClickListener(); | ||||
|  | ||||
|         subscriptions.add(db.manga.getWithUnread() | ||||
|         subscriptions.add(db.getMangasWithUnread() | ||||
|                         .observeOn(mainThread()) | ||||
|                         .subscribe(adapter::setNewItems) | ||||
|         ); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onQueryTextChange(String query) { | ||||
| @@ -68,7 +70,7 @@ public class LibraryPresenter extends BasePresenter { | ||||
|                 .map(checkedItems::keyAt) | ||||
|                 .map(adapter::getItem) | ||||
|                 .toList() | ||||
|                 .flatMap(db.manga::delete) | ||||
|                 .flatMap(db::deleteMangas) | ||||
|                 .subscribe(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ public class MangaDetailPresenter extends BasePresenter { | ||||
|     } | ||||
|  | ||||
|     public void initializeChapters(Manga manga) { | ||||
|         db.chapter.get(manga) | ||||
|         db.getChapters(manga) | ||||
|                 .subscribe(view::setChapters); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package eu.kanade.mangafeed.sources; | ||||
|  | ||||
| import com.squareup.okhttp.Headers; | ||||
| import com.squareup.okhttp.Response; | ||||
|  | ||||
| import org.jsoup.Jsoup; | ||||
| 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.helpers.NetworkHelper; | ||||
| import eu.kanade.mangafeed.data.helpers.SourceManager; | ||||
| import eu.kanade.mangafeed.data.models.Chapter; | ||||
| import eu.kanade.mangafeed.data.models.Manga; | ||||
| import rx.Observable; | ||||
| import rx.functions.Func1; | ||||
| 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 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 Headers constructRequestHeaders() { | ||||
| @@ -105,38 +103,32 @@ public class Batoto { | ||||
|         return Observable.just(genres); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     public Observable<UpdatePageMarker> pullLatestUpdatesFromNetwork(final UpdatePageMarker newUpdate) { | ||||
|         return mNetworkService | ||||
|                 .getResponse(newUpdate.getNextPageUrl(), NetworkModule.NULL_CACHE_CONTROL, REQUEST_HEADERS) | ||||
|                 .flatMap(new Func1<Response, Observable<String>>() { | ||||
|                     @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)); | ||||
|                     } | ||||
|                 }); | ||||
|     public String getUrlFromPageNumber(int page) { | ||||
|         if (page == 1) | ||||
|             return INITIAL_UPDATE_URL; | ||||
|  | ||||
|         return INITIAL_UPDATE_URL.substring(0, INITIAL_UPDATE_URL.length() - 1) + page; | ||||
|     } | ||||
|  | ||||
|     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); | ||||
|  | ||||
|         List<Manga> updatedMangaList = scrapeUpdateMangasFromParsedDocument(parsedDocument); | ||||
|         updateLibraryInDatabase(updatedMangaList); | ||||
|         //updateLibraryInDatabase(updatedMangaList); | ||||
|  | ||||
|         String nextPageUrl = findNextUrlFromParsedDocument(requestUrl, unparsedHtml); | ||||
|         int lastMangaPostion = updatedMangaList.size(); | ||||
|  | ||||
|         return new UpdatePageMarker(nextPageUrl, lastMangaPostion); | ||||
|         return updatedMangaList; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     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])"); | ||||
|         for (Element currentHtmlBlock : updatedHtmlBlocks) { | ||||
| @@ -149,29 +141,27 @@ public class Batoto { | ||||
|     } | ||||
|  | ||||
|     private Manga constructMangaFromHtmlBlock(Element htmlBlock) { | ||||
|         Manga mangaFromHtmlBlock = DefaultFactory.Manga.constructDefault(); | ||||
|         mangaFromHtmlBlock.setSource(NAME); | ||||
|         Manga mangaFromHtmlBlock = new Manga(); | ||||
|  | ||||
|         Element urlElement = htmlBlock.select("a[href^=http://bato.to]").first(); | ||||
|         Element nameElement = urlElement; | ||||
|         Element updateElement = htmlBlock.select("td").get(5); | ||||
|  | ||||
|         mangaFromHtmlBlock.source = SourceManager.BATOTO; | ||||
|  | ||||
|         if (urlElement != null) { | ||||
|             String fieldUrl = urlElement.attr("href"); | ||||
|             mangaFromHtmlBlock.setUrl(fieldUrl); | ||||
|             mangaFromHtmlBlock.url = fieldUrl; | ||||
|         } | ||||
|         if (nameElement != null) { | ||||
|             String fieldName = nameElement.text().trim(); | ||||
|             mangaFromHtmlBlock.setName(fieldName); | ||||
|             mangaFromHtmlBlock.title = fieldName; | ||||
|         } | ||||
|         if (updateElement != null) { | ||||
|             long fieldUpdate = parseUpdateFromElement(updateElement); | ||||
|             mangaFromHtmlBlock.setUpdated(fieldUpdate); | ||||
|             mangaFromHtmlBlock.last_update = fieldUpdate; | ||||
|         } | ||||
|  | ||||
|         int updateCount = 1; | ||||
|         mangaFromHtmlBlock.setUpdateCount(updateCount); | ||||
|  | ||||
|         return mangaFromHtmlBlock; | ||||
|     } | ||||
|  | ||||
| @@ -186,9 +176,11 @@ public class Batoto { | ||||
|             // Do Nothing. | ||||
|         } | ||||
|  | ||||
|         return DefaultFactory.Manga.DEFAULT_UPDATED; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|  | ||||
|     private void updateLibraryInDatabase(List<Manga> mangaList) { | ||||
|         mQueryManager.beginLibraryTransaction(); | ||||
|         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; | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user