From 8dca7fe79a1d808c7583d929fb4b445a0b1a1bef Mon Sep 17 00:00:00 2001 From: inorichi Date: Mon, 14 Dec 2015 13:24:05 +0100 Subject: [PATCH] Improve MAL support (UI is very simple yet). --- app/src/main/AndroidManifest.xml | 2 +- .../data/chaptersync/BaseChapterSync.java | 21 -- .../data/chaptersync/MyAnimeList.java | 163 ----------- .../data/database/DatabaseHelper.java | 42 +-- .../mangafeed/data/database/DbOpenHelper.java | 10 +- .../data/database/models/ChapterSync.java | 35 --- .../data/database/models/MangaSync.java | 41 +++ ...pterSyncTable.java => MangaSyncTable.java} | 10 +- .../MangaSyncManager.java} | 15 +- .../data/mangasync/base/BaseMangaSync.java | 28 ++ .../data/mangasync/services/MyAnimeList.java | 256 ++++++++++++++++++ .../data/preference/PreferencesHelper.java | 25 +- .../UpdateMangaSyncService.java} | 28 +- .../event/UpdateChapterSyncEvent.java | 17 -- .../mangafeed/event/UpdateMangaSyncEvent.java | 17 ++ .../injection/component/AppComponent.java | 6 +- .../injection/module/DataModule.java | 6 +- .../ui/library/LibraryPresenter.java | 2 +- .../mangafeed/ui/manga/MangaActivity.java | 6 +- .../MyAnimeListDialogFragment.java | 42 +-- .../myanimelist/MyAnimeListFragment.java | 19 +- .../myanimelist/MyAnimeListPresenter.java | 53 ++-- .../mangafeed/ui/reader/ReaderPresenter.java | 28 +- .../ui/setting/SettingsAccountsFragment.java | 20 +- ...nDialog.java => MangaSyncLoginDialog.java} | 16 +- .../main/res/layout/fragment_myanimelist.xml | 37 ++- app/src/main/res/values/arrays.xml | 2 +- app/src/main/res/values/keys.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/xml/pref_downloads.xml | 10 +- 30 files changed, 569 insertions(+), 392 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/mangafeed/data/chaptersync/BaseChapterSync.java delete mode 100644 app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java delete mode 100644 app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/data/database/models/MangaSync.java rename app/src/main/java/eu/kanade/mangafeed/data/database/tables/{ChapterSyncTable.java => MangaSyncTable.java} (78%) rename app/src/main/java/eu/kanade/mangafeed/data/{chaptersync/ChapterSyncManager.java => mangasync/MangaSyncManager.java} (57%) create mode 100644 app/src/main/java/eu/kanade/mangafeed/data/mangasync/base/BaseMangaSync.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/data/mangasync/services/MyAnimeList.java rename app/src/main/java/eu/kanade/mangafeed/data/{chaptersync/UpdateChapterSyncService.java => sync/UpdateMangaSyncService.java} (63%) delete mode 100644 app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/event/UpdateMangaSyncEvent.java rename app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/{ChapterSyncLoginDialog.java => MangaSyncLoginDialog.java} (78%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 50f2b8608..e3b445d48 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,7 +52,7 @@ - login(String username, String password); - - public abstract boolean isLogged(); - - public abstract Observable update(ChapterSync chapter); -} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java b/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java deleted file mode 100644 index 9786d0427..000000000 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/MyAnimeList.java +++ /dev/null @@ -1,163 +0,0 @@ -package eu.kanade.mangafeed.data.chaptersync; - -import android.content.Context; -import android.net.Uri; -import android.util.Xml; - -import com.squareup.okhttp.Credentials; -import com.squareup.okhttp.FormEncodingBuilder; -import com.squareup.okhttp.Headers; -import com.squareup.okhttp.Response; - -import org.jsoup.Jsoup; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.List; - -import javax.inject.Inject; - -import eu.kanade.mangafeed.App; -import eu.kanade.mangafeed.data.database.models.ChapterSync; -import eu.kanade.mangafeed.data.network.NetworkHelper; -import eu.kanade.mangafeed.data.preference.PreferencesHelper; -import rx.Observable; - -public class MyAnimeList extends BaseChapterSync { - - @Inject PreferencesHelper preferences; - @Inject NetworkHelper networkService; - - private Headers headers; - - public static final String BASE_URL = "http://myanimelist.net"; - - private static final String ENTRY = "entry"; - private static final String CHAPTER = "chapter"; - - public MyAnimeList(Context context) { - App.get(context).getComponent().inject(this); - - String username = preferences.getChapterSyncUsername(this); - String password = preferences.getChapterSyncPassword(this); - - if (!username.isEmpty() && !password.isEmpty()) { - createHeaders(username, password); - } - } - - @Override - public String getName() { - return "MyAnimeList"; - } - - @Override - public int getId() { - return ChapterSyncManager.MYANIMELIST; - } - - public String getLoginUrl() { - return Uri.parse(BASE_URL).buildUpon() - .appendEncodedPath("api/account/verify_credentials.xml") - .toString(); - } - - public Observable login(String username, String password) { - createHeaders(username, password); - return networkService.getResponse(getLoginUrl(), headers, null) - .map(response -> response.code() == 200); - } - - @Override - public boolean isLogged() { - return !preferences.getChapterSyncUsername(this).isEmpty() - && !preferences.getChapterSyncPassword(this).isEmpty(); - } - - public String getSearchUrl(String query) { - return Uri.parse(BASE_URL).buildUpon() - .appendEncodedPath("api/manga/search.xml") - .appendQueryParameter("q", query) - .toString(); - } - - public Observable> search(String query) { - return networkService.getStringResponse(getSearchUrl(query), headers, null) - .map(Jsoup::parse) - .flatMap(doc -> Observable.from(doc.select("entry"))) - .map(entry -> { - ChapterSync chapter = ChapterSync.create(this); - chapter.title = entry.select("title").first().text(); - chapter.remote_id = Integer.parseInt(entry.select("id").first().text()); - return chapter; - }) - .toList(); - } - - public String getListUrl(String username) { - return Uri.parse(BASE_URL).buildUpon() - .appendPath("malappinfo.php") - .appendQueryParameter("u", username) - .appendQueryParameter("status", "all") - .appendQueryParameter("type", "manga") - .toString(); - } - - public Observable> getList(String username) { - return networkService.getStringResponse(getListUrl(username), headers, null) - .map(Jsoup::parse) - .flatMap(doc -> Observable.from(doc.select("manga"))) - .map(entry -> { - ChapterSync chapter = ChapterSync.create(this); - chapter.title = entry.select("series_title").first().text(); - chapter.remote_id = Integer.parseInt( - entry.select("series_mangadb_id").first().text()); - chapter.last_chapter_read = Integer.parseInt( - entry.select("my_read_chapters").first().text()); - return chapter; - }) - .toList(); - } - - public String getUpdateUrl(ChapterSync chapter) { - return Uri.parse(BASE_URL).buildUpon() - .appendEncodedPath("api/mangalist/update") - .appendPath(chapter.remote_id + ".xml") - .toString(); - } - - public Observable update(ChapterSync chapter) { - XmlSerializer xml = Xml.newSerializer(); - StringWriter writer = new StringWriter(); - try { - xml.setOutput(writer); - xml.startDocument("UTF-8", false); - xml.startTag("", ENTRY); - xml.startTag("", CHAPTER); - xml.text(chapter.last_chapter_read + ""); - xml.endTag("", CHAPTER); - xml.endTag("", ENTRY); - xml.endDocument(); - } catch (IOException e) { - return Observable.error(e); - } - - FormEncodingBuilder form = new FormEncodingBuilder(); - form.add("data", writer.toString()); - - return networkService.postData(getUpdateUrl(chapter), form.build(), headers); - } - - public void createHeaders(String username, String password) { - Headers.Builder builder = new Headers.Builder(); - builder.add("Authorization", Credentials.basic(username, password)); -// builder.add("User-Agent", ""); - setHeaders(builder.build()); - } - - public void setHeaders(Headers headers) { - this.headers = headers; - } - -} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java b/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java index 779f692d0..0fe2a1261 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java @@ -16,21 +16,21 @@ import com.pushtorefresh.storio.sqlite.queries.RawQuery; import java.util.List; -import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; +import eu.kanade.mangafeed.data.database.models.MangaSync; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; import eu.kanade.mangafeed.data.database.models.Chapter; import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteDeleteResolver; import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteGetResolver; import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLitePutResolver; -import eu.kanade.mangafeed.data.database.models.ChapterSync; -import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLiteDeleteResolver; -import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLiteGetResolver; -import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLitePutResolver; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteDeleteResolver; import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteGetResolver; import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLitePutResolver; +import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteDeleteResolver; +import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteGetResolver; +import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLitePutResolver; import eu.kanade.mangafeed.data.database.resolvers.MangaWithUnreadGetResolver; -import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable; +import eu.kanade.mangafeed.data.database.tables.MangaSyncTable; import eu.kanade.mangafeed.data.database.tables.ChapterTable; import eu.kanade.mangafeed.data.database.tables.MangaTable; import eu.kanade.mangafeed.util.ChapterRecognition; @@ -55,10 +55,10 @@ public class DatabaseHelper { .getResolver(new ChapterStorIOSQLiteGetResolver()) .deleteResolver(new ChapterStorIOSQLiteDeleteResolver()) .build()) - .addTypeMapping(ChapterSync.class, SQLiteTypeMapping.builder() - .putResolver(new ChapterSyncStorIOSQLitePutResolver()) - .getResolver(new ChapterSyncStorIOSQLiteGetResolver()) - .deleteResolver(new ChapterSyncStorIOSQLiteDeleteResolver()) + .addTypeMapping(MangaSync.class, SQLiteTypeMapping.builder() + .putResolver(new MangaSyncStorIOSQLitePutResolver()) + .getResolver(new MangaSyncStorIOSQLiteGetResolver()) + .deleteResolver(new MangaSyncStorIOSQLiteDeleteResolver()) .build()) .build(); } @@ -88,7 +88,7 @@ public class DatabaseHelper { .prepare(); } - public PreparedGetListOfObjects getMangasWithUnread() { + public PreparedGetListOfObjects getFavoriteMangasWithUnread() { return db.get() .listOfObjects(Manga.class) .withQuery(RawQuery.builder() @@ -301,30 +301,30 @@ public class DatabaseHelper { .prepare(); } - // Chapter sync related queries + // Manga sync related queries - public PreparedGetListOfObjects getChapterSync(Manga manga, BaseChapterSync sync) { + public PreparedGetListOfObjects getMangaSync(Manga manga, BaseMangaSync sync) { return db.get() - .listOfObjects(ChapterSync.class) + .listOfObjects(MangaSync.class) .withQuery(Query.builder() - .table(ChapterSyncTable.TABLE) - .where(ChapterSyncTable.COLUMN_MANGA_ID + "=? AND " + - ChapterSyncTable.COLUMN_SYNC_ID + "=?") + .table(MangaSyncTable.TABLE) + .where(MangaSyncTable.COLUMN_MANGA_ID + "=? AND " + + MangaSyncTable.COLUMN_SYNC_ID + "=?") .whereArgs(manga.id, sync.getId()) .build()) .prepare(); } - public PreparedPutObject insertChapterSync(ChapterSync chapter) { + public PreparedPutObject insertMangaSync(MangaSync manga) { return db.put() - .object(chapter) + .object(manga) .prepare(); } - public PreparedDeleteObject deleteChapterSync(ChapterSync chapter) { + public PreparedDeleteObject deleteMangaSync(MangaSync manga) { return db.delete() - .object(chapter) + .object(manga) .prepare(); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/DbOpenHelper.java b/app/src/main/java/eu/kanade/mangafeed/data/database/DbOpenHelper.java index 95a2a9473..a5f4bf149 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/DbOpenHelper.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/DbOpenHelper.java @@ -5,14 +5,14 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.support.annotation.NonNull; -import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable; +import eu.kanade.mangafeed.data.database.tables.MangaSyncTable; import eu.kanade.mangafeed.data.database.tables.ChapterTable; import eu.kanade.mangafeed.data.database.tables.MangaTable; public class DbOpenHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "mangafeed.db"; - public static final int DATABASE_VERSION = 2; + public static final int DATABASE_VERSION = 3; public DbOpenHelper(@NonNull Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -22,13 +22,13 @@ public class DbOpenHelper extends SQLiteOpenHelper { public void onCreate(@NonNull SQLiteDatabase db) { db.execSQL(MangaTable.getCreateTableQuery()); db.execSQL(ChapterTable.getCreateTableQuery()); - db.execSQL(ChapterSyncTable.getCreateTableQuery()); + db.execSQL(MangaSyncTable.getCreateTableQuery()); } @Override public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion == 1) - db.execSQL(ChapterSyncTable.getCreateTableQuery()); + if (oldVersion < 3) + db.execSQL(MangaSyncTable.getCreateTableQuery()); } @Override diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java b/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java deleted file mode 100644 index 7a0897bfb..000000000 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/models/ChapterSync.java +++ /dev/null @@ -1,35 +0,0 @@ -package eu.kanade.mangafeed.data.database.models; - -import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn; -import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType; - -import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; -import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable; - -@StorIOSQLiteType(table = ChapterSyncTable.TABLE) -public class ChapterSync { - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_ID, key = true) - public long id; - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_MANGA_ID) - public long manga_id; - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_SYNC_ID) - public int sync_id; - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID) - public int remote_id; - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_TITLE) - public String title; - - @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_LAST_CHAPTER_READ) - public int last_chapter_read; - - public static ChapterSync create(BaseChapterSync sync) { - ChapterSync chapter = new ChapterSync(); - chapter.sync_id = sync.getId(); - return chapter; - } -} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/models/MangaSync.java b/app/src/main/java/eu/kanade/mangafeed/data/database/models/MangaSync.java new file mode 100644 index 000000000..9cbb87f73 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/models/MangaSync.java @@ -0,0 +1,41 @@ +package eu.kanade.mangafeed.data.database.models; + +import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn; +import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType; + +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; +import eu.kanade.mangafeed.data.database.tables.MangaSyncTable; + +@StorIOSQLiteType(table = MangaSyncTable.TABLE) +public class MangaSync { + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_ID, key = true) + public Long id; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_MANGA_ID) + public long manga_id; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_SYNC_ID) + public int sync_id; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_REMOTE_ID) + public int remote_id; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_TITLE) + public String title; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_LAST_CHAPTER_READ) + public int last_chapter_read; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_SCORE) + public float score; + + @StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_STATUS) + public int status; + + public static MangaSync create(BaseMangaSync service) { + MangaSync mangasync = new MangaSync(); + mangasync.sync_id = service.getId(); + return mangasync; + } +} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/tables/ChapterSyncTable.java b/app/src/main/java/eu/kanade/mangafeed/data/database/tables/MangaSyncTable.java similarity index 78% rename from app/src/main/java/eu/kanade/mangafeed/data/database/tables/ChapterSyncTable.java rename to app/src/main/java/eu/kanade/mangafeed/data/database/tables/MangaSyncTable.java index 98bb75501..6e2a679ad 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/tables/ChapterSyncTable.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/tables/MangaSyncTable.java @@ -2,9 +2,9 @@ package eu.kanade.mangafeed.data.database.tables; import android.support.annotation.NonNull; -public class ChapterSyncTable { +public class MangaSyncTable { - public static final String TABLE = "chapter_sync"; + public static final String TABLE = "manga_sync"; public static final String COLUMN_ID = "_id"; @@ -18,6 +18,10 @@ public class ChapterSyncTable { public static final String COLUMN_LAST_CHAPTER_READ = "last_chapter_read"; + public static final String COLUMN_STATUS = "status"; + + public static final String COLUMN_SCORE = "score"; + @NonNull public static String getCreateTableQuery() { return "CREATE TABLE " + TABLE + "(" @@ -27,6 +31,8 @@ public class ChapterSyncTable { + COLUMN_REMOTE_ID + " INTEGER NOT NULL, " + COLUMN_TITLE + " TEXT NOT NULL, " + COLUMN_LAST_CHAPTER_READ + " INTEGER NOT NULL, " + + COLUMN_STATUS + " INTEGER NOT NULL, " + + COLUMN_SCORE + " FLOAT NOT NULL, " + "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangaTable.TABLE + "(" + MangaTable.COLUMN_ID + ") " + "ON DELETE CASCADE" + ");"; diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/MangaSyncManager.java similarity index 57% rename from app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java rename to app/src/main/java/eu/kanade/mangafeed/data/mangasync/MangaSyncManager.java index e38f3faa4..065ad30eb 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/ChapterSyncManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/MangaSyncManager.java @@ -1,18 +1,21 @@ -package eu.kanade.mangafeed.data.chaptersync; +package eu.kanade.mangafeed.data.mangasync; import android.content.Context; import java.util.ArrayList; import java.util.List; -public class ChapterSyncManager { +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; +import eu.kanade.mangafeed.data.mangasync.services.MyAnimeList; - private List services; +public class MangaSyncManager { + + private List services; private MyAnimeList myAnimeList; public static final int MYANIMELIST = 1; - public ChapterSyncManager(Context context) { + public MangaSyncManager(Context context) { services = new ArrayList<>(); myAnimeList = new MyAnimeList(context); services.add(myAnimeList); @@ -22,11 +25,11 @@ public class ChapterSyncManager { return myAnimeList; } - public List getChapterSyncServices() { + public List getSyncServices() { return services; } - public BaseChapterSync getSyncService(int id) { + public BaseMangaSync getSyncService(int id) { switch (id) { case MYANIMELIST: return myAnimeList; diff --git a/app/src/main/java/eu/kanade/mangafeed/data/mangasync/base/BaseMangaSync.java b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/base/BaseMangaSync.java new file mode 100644 index 000000000..97562ac90 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/base/BaseMangaSync.java @@ -0,0 +1,28 @@ +package eu.kanade.mangafeed.data.mangasync.base; + +import com.squareup.okhttp.Response; + +import eu.kanade.mangafeed.data.database.models.MangaSync; +import rx.Observable; + +public abstract class BaseMangaSync { + + // Name of the manga sync service to display + public abstract String getName(); + + // Id of the sync service (must be declared and obtained from MangaSyncManager to avoid conflicts) + public abstract int getId(); + + public abstract Observable login(String username, String password); + + public abstract boolean isLogged(); + + public abstract Observable update(MangaSync manga); + + public abstract Observable add(MangaSync manga); + + public abstract Observable bind(MangaSync manga); + + public abstract String getStatus(int status); + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/mangasync/services/MyAnimeList.java b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/services/MyAnimeList.java new file mode 100644 index 000000000..8f1c6910a --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/data/mangasync/services/MyAnimeList.java @@ -0,0 +1,256 @@ +package eu.kanade.mangafeed.data.mangasync.services; + +import android.content.Context; +import android.net.Uri; +import android.util.Xml; + +import com.squareup.okhttp.Credentials; +import com.squareup.okhttp.FormEncodingBuilder; +import com.squareup.okhttp.Headers; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; + +import org.jsoup.Jsoup; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; + +import javax.inject.Inject; + +import eu.kanade.mangafeed.App; +import eu.kanade.mangafeed.data.database.models.MangaSync; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; +import eu.kanade.mangafeed.data.network.NetworkHelper; +import eu.kanade.mangafeed.data.preference.PreferencesHelper; +import rx.Observable; + +public class MyAnimeList extends BaseMangaSync { + + @Inject PreferencesHelper preferences; + @Inject NetworkHelper networkService; + + private Headers headers; + private String username; + + public static final String BASE_URL = "http://myanimelist.net"; + + private static final String ENTRY_TAG = "entry"; + private static final String CHAPTER_TAG = "chapter"; + private static final String SCORE_TAG = "score"; + private static final String STATUS_TAG = "status"; + + public static final int NOT_IN_LIST = 0; + public static final int READING = 1; + public static final int COMPLETED = 2; + public static final int ON_HOLD = 3; + public static final int DROPPED = 4; + public static final int PLAN_TO_READ = 6; + + public static final int DEFAULT_STATUS = READING; + public static final int DEFAULT_SCORE = 0; + + public MyAnimeList(Context context) { + App.get(context).getComponent().inject(this); + + String username = preferences.getMangaSyncUsername(this); + String password = preferences.getMangaSyncPassword(this); + + if (!username.isEmpty() && !password.isEmpty()) { + createHeaders(username, password); + } + } + + @Override + public String getName() { + return "MyAnimeList"; + } + + @Override + public int getId() { + return MangaSyncManager.MYANIMELIST; + } + + public String getLoginUrl() { + return Uri.parse(BASE_URL).buildUpon() + .appendEncodedPath("api/account/verify_credentials.xml") + .toString(); + } + + public Observable login(String username, String password) { + createHeaders(username, password); + return networkService.getResponse(getLoginUrl(), headers, null) + .map(response -> response.code() == 200); + } + + @Override + public boolean isLogged() { + return !preferences.getMangaSyncUsername(this).isEmpty() + && !preferences.getMangaSyncPassword(this).isEmpty(); + } + + public String getSearchUrl(String query) { + return Uri.parse(BASE_URL).buildUpon() + .appendEncodedPath("api/manga/search.xml") + .appendQueryParameter("q", query) + .toString(); + } + + public Observable> search(String query) { + return networkService.getStringResponse(getSearchUrl(query), headers, null) + .map(Jsoup::parse) + .flatMap(doc -> Observable.from(doc.select("entry"))) + .map(entry -> { + MangaSync manga = MangaSync.create(this); + manga.title = entry.select("title").first().text(); + manga.remote_id = Integer.parseInt(entry.select("id").first().text()); + return manga; + }) + .toList(); + } + + public String getListUrl(String username) { + return Uri.parse(BASE_URL).buildUpon() + .appendPath("malappinfo.php") + .appendQueryParameter("u", username) + .appendQueryParameter("status", "all") + .appendQueryParameter("type", "manga") + .toString(); + } + + public Observable> getList(String username) { + // TODO cache this list for a few minutes + return networkService.getStringResponse(getListUrl(username), headers, null) + .map(Jsoup::parse) + .flatMap(doc -> Observable.from(doc.select("manga"))) + .map(entry -> { + MangaSync manga = MangaSync.create(this); + manga.title = entry.select("series_title").first().text(); + manga.remote_id = Integer.parseInt( + entry.select("series_mangadb_id").first().text()); + manga.last_chapter_read = Integer.parseInt( + entry.select("my_read_chapters").first().text()); + manga.status = Integer.parseInt( + entry.select("my_status").first().text()); + // MAL doesn't support score with decimals + manga.score = Integer.parseInt( + entry.select("my_score").first().text()); + return manga; + }) + .toList(); + } + + public String getUpdateUrl(MangaSync manga) { + return Uri.parse(BASE_URL).buildUpon() + .appendEncodedPath("api/mangalist/update") + .appendPath(manga.remote_id + ".xml") + .toString(); + } + + public Observable update(MangaSync manga) { + try { + RequestBody payload = getMangaPostPayload(manga); + return networkService.postData(getUpdateUrl(manga), payload, headers); + } catch (IOException e) { + return Observable.error(e); + } + } + + public String getAddUrl(MangaSync manga) { + return Uri.parse(BASE_URL).buildUpon() + .appendEncodedPath("api/mangalist/add") + .appendPath(manga.remote_id + ".xml") + .toString(); + } + + public Observable add(MangaSync manga) { + try { + RequestBody payload = getMangaPostPayload(manga); + return networkService.postData(getAddUrl(manga), payload, headers); + } catch (IOException e) { + return Observable.error(e); + } + } + + private RequestBody getMangaPostPayload(MangaSync manga) throws IOException { + XmlSerializer xml = Xml.newSerializer(); + StringWriter writer = new StringWriter(); + xml.setOutput(writer); + xml.startDocument("UTF-8", false); + xml.startTag("", ENTRY_TAG); + + // Last chapter read + if (manga.last_chapter_read != 0) { + xml.startTag("", CHAPTER_TAG); + xml.text(manga.last_chapter_read + ""); + xml.endTag("", CHAPTER_TAG); + } + // Manga status in the list + xml.startTag("", STATUS_TAG); + xml.text(manga.status + ""); + xml.endTag("", STATUS_TAG); + // Manga score + xml.startTag("", SCORE_TAG); + xml.text(manga.score + ""); + xml.endTag("", SCORE_TAG); + + xml.endTag("", ENTRY_TAG); + xml.endDocument(); + + FormEncodingBuilder form = new FormEncodingBuilder(); + form.add("data", writer.toString()); + return form.build(); + } + + public Observable bind(MangaSync manga) { + return getList(username) + .flatMap(list -> { + manga.sync_id = getId(); + for (MangaSync remoteManga : list) { + if (remoteManga.remote_id == manga.remote_id) { + // Manga is already in the list + manga.score = remoteManga.score; + manga.status = remoteManga.status; + manga.last_chapter_read = remoteManga.last_chapter_read; + return update(manga); + } + } + // Set default fields if it's not found in the list + manga.score = DEFAULT_SCORE; + manga.status = DEFAULT_STATUS; + return add(manga); + }); + } + + @Override + public String getStatus(int status) { + switch (status) { + case READING: + return "Reading"; + case COMPLETED: + return "Completed"; + case ON_HOLD: + return "On hold"; + case DROPPED: + return "Dropped"; + case PLAN_TO_READ: + return "Plan to read"; + } + return ""; + } + + public void createHeaders(String username, String password) { + this.username = username; + Headers.Builder builder = new Headers.Builder(); + builder.add("Authorization", Credentials.basic(username, password)); + builder.add("User-Agent", "api-indiv-9F93C52A963974CF674325391990191C"); + setHeaders(builder.build()); + } + + public void setHeaders(Headers headers) { + this.headers = headers; + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java b/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java index 6a57da63a..8f37e0c51 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java @@ -11,7 +11,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences; import java.io.File; import eu.kanade.mangafeed.R; -import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; import eu.kanade.mangafeed.data.source.base.Source; import rx.Observable; @@ -23,8 +23,8 @@ public class PreferencesHelper { private static final String SOURCE_ACCOUNT_USERNAME = "pref_source_username_"; private static final String SOURCE_ACCOUNT_PASSWORD = "pref_source_password_"; - private static final String CHAPTERSYNC_ACCOUNT_USERNAME = "pref_chaptersync_username_"; - private static final String CHAPTERSYNC_ACCOUNT_PASSWORD = "pref_chaptersync_password_"; + private static final String MANGASYNC_ACCOUNT_USERNAME = "pref_mangasync_username_"; + private static final String MANGASYNC_ACCOUNT_PASSWORD = "pref_mangasync_password_"; private File defaultDownloadsDir; @@ -102,18 +102,18 @@ public class PreferencesHelper { .apply(); } - public String getChapterSyncUsername(BaseChapterSync sync) { - return prefs.getString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), ""); + public String getMangaSyncUsername(BaseMangaSync sync) { + return prefs.getString(MANGASYNC_ACCOUNT_USERNAME + sync.getId(), ""); } - public String getChapterSyncPassword(BaseChapterSync sync) { - return prefs.getString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), ""); + public String getMangaSyncPassword(BaseMangaSync sync) { + return prefs.getString(MANGASYNC_ACCOUNT_PASSWORD + sync.getId(), ""); } - public void setChapterSyncCredentials(BaseChapterSync sync, String username, String password) { + public void setMangaSyncCredentials(BaseMangaSync sync, String username, String password) { prefs.edit() - .putString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), username) - .putString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), password) + .putString(MANGASYNC_ACCOUNT_USERNAME + sync.getId(), username) + .putString(MANGASYNC_ACCOUNT_PASSWORD + sync.getId(), password) .apply(); } @@ -127,12 +127,11 @@ public class PreferencesHelper { } public int getDownloadThreads() { - return Integer.parseInt(prefs.getString(getKey(R.string.pref_download_threads_key), "1")); + return prefs.getInt(getKey(R.string.pref_download_slots_key), 1); } public Observable getDownloadTheadsObservable() { - return rxPrefs.getString(getKey(R.string.pref_download_threads_key), "1") - .asObservable().map(Integer::parseInt); + return rxPrefs.getInteger(getKey(R.string.pref_download_slots_key), 1).asObservable(); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java b/app/src/main/java/eu/kanade/mangafeed/data/sync/UpdateMangaSyncService.java similarity index 63% rename from app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java rename to app/src/main/java/eu/kanade/mangafeed/data/sync/UpdateMangaSyncService.java index c313355e1..3c974a25e 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/chaptersync/UpdateChapterSyncService.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/sync/UpdateMangaSyncService.java @@ -1,4 +1,4 @@ -package eu.kanade.mangafeed.data.chaptersync; +package eu.kanade.mangafeed.data.sync; import android.app.Service; import android.content.Context; @@ -10,24 +10,24 @@ import javax.inject.Inject; import de.greenrobot.event.EventBus; import eu.kanade.mangafeed.App; import eu.kanade.mangafeed.data.database.DatabaseHelper; -import eu.kanade.mangafeed.data.database.models.ChapterSync; -import eu.kanade.mangafeed.data.network.NetworkHelper; -import eu.kanade.mangafeed.event.UpdateChapterSyncEvent; +import eu.kanade.mangafeed.data.database.models.MangaSync; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; +import eu.kanade.mangafeed.event.UpdateMangaSyncEvent; import eu.kanade.mangafeed.util.EventBusHook; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; -public class UpdateChapterSyncService extends Service { +public class UpdateMangaSyncService extends Service { - @Inject ChapterSyncManager syncManager; - @Inject NetworkHelper networkManager; + @Inject MangaSyncManager syncManager; @Inject DatabaseHelper db; private CompositeSubscription subscriptions; public static void start(Context context) { - context.startService(new Intent(context, UpdateChapterSyncService.class)); + context.startService(new Intent(context, UpdateMangaSyncService.class)); } @Override @@ -56,15 +56,15 @@ public class UpdateChapterSyncService extends Service { } @EventBusHook - public void onEventMainThread(UpdateChapterSyncEvent event) { - updateLastChapteRead(event.getChapterSync()); + public void onEventMainThread(UpdateMangaSyncEvent event) { + updateLastChapteRead(event.getMangaSync()); } - private void updateLastChapteRead(ChapterSync chapterSync) { - BaseChapterSync sync = syncManager.getSyncService(chapterSync.sync_id); + private void updateLastChapteRead(MangaSync mangaSync) { + BaseMangaSync sync = syncManager.getSyncService(mangaSync.sync_id); - subscriptions.add(sync.update(chapterSync) - .flatMap(response -> db.insertChapterSync(chapterSync).createObservable()) + subscriptions.add(sync.update(mangaSync) + .flatMap(response -> db.insertMangaSync(mangaSync).createObservable()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { diff --git a/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java b/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java deleted file mode 100644 index 965e10bb1..000000000 --- a/app/src/main/java/eu/kanade/mangafeed/event/UpdateChapterSyncEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.kanade.mangafeed.event; - -import eu.kanade.mangafeed.data.database.models.ChapterSync; - -public class UpdateChapterSyncEvent { - - private ChapterSync chapterSync; - - public UpdateChapterSyncEvent(ChapterSync chapterSync) { - this.chapterSync = chapterSync; - } - - public ChapterSync getChapterSync() { - return chapterSync; - } - -} diff --git a/app/src/main/java/eu/kanade/mangafeed/event/UpdateMangaSyncEvent.java b/app/src/main/java/eu/kanade/mangafeed/event/UpdateMangaSyncEvent.java new file mode 100644 index 000000000..8fb9a06ab --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/event/UpdateMangaSyncEvent.java @@ -0,0 +1,17 @@ +package eu.kanade.mangafeed.event; + +import eu.kanade.mangafeed.data.database.models.MangaSync; + +public class UpdateMangaSyncEvent { + + private MangaSync mangaSync; + + public UpdateMangaSyncEvent(MangaSync mangaSync) { + this.mangaSync = mangaSync; + } + + public MangaSync getMangaSync() { + return mangaSync; + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java index 9df2b49f5..1bef652e5 100644 --- a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java +++ b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java @@ -5,8 +5,8 @@ import android.app.Application; import javax.inject.Singleton; import dagger.Component; -import eu.kanade.mangafeed.data.chaptersync.MyAnimeList; -import eu.kanade.mangafeed.data.chaptersync.UpdateChapterSyncService; +import eu.kanade.mangafeed.data.mangasync.services.MyAnimeList; +import eu.kanade.mangafeed.data.sync.UpdateMangaSyncService; import eu.kanade.mangafeed.data.download.DownloadService; import eu.kanade.mangafeed.data.source.base.Source; import eu.kanade.mangafeed.data.sync.LibraryUpdateService; @@ -56,7 +56,7 @@ public interface AppComponent { void inject(LibraryUpdateService libraryUpdateService); void inject(DownloadService downloadService); - void inject(UpdateChapterSyncService updateChapterSyncService); + void inject(UpdateMangaSyncService updateMangaSyncService); Application application(); diff --git a/app/src/main/java/eu/kanade/mangafeed/injection/module/DataModule.java b/app/src/main/java/eu/kanade/mangafeed/injection/module/DataModule.java index 171e3ffa1..0b8abe8e1 100644 --- a/app/src/main/java/eu/kanade/mangafeed/injection/module/DataModule.java +++ b/app/src/main/java/eu/kanade/mangafeed/injection/module/DataModule.java @@ -8,7 +8,7 @@ import dagger.Module; import dagger.Provides; import eu.kanade.mangafeed.data.cache.CacheManager; import eu.kanade.mangafeed.data.cache.CoverCache; -import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; import eu.kanade.mangafeed.data.database.DatabaseHelper; import eu.kanade.mangafeed.data.download.DownloadManager; import eu.kanade.mangafeed.data.network.NetworkHelper; @@ -66,8 +66,8 @@ public class DataModule { @Provides @Singleton - ChapterSyncManager provideChapterSyncManager(Application app) { - return new ChapterSyncManager(app); + MangaSyncManager provideMangaSyncManager(Application app) { + return new MangaSyncManager(app); } } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java index a6212eb49..a1c5664f7 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java @@ -28,7 +28,7 @@ public class LibraryPresenter extends BasePresenter { super.onCreate(savedState); restartableLatestCache(GET_MANGAS, - () -> db.getMangasWithUnread().createObservable() + () -> db.getFavoriteMangasWithUnread().createObservable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()), LibraryFragment::onNextMangas); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java index a0a2f751c..014a4165a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java @@ -17,7 +17,7 @@ import butterknife.Bind; import butterknife.ButterKnife; import eu.kanade.mangafeed.App; import eu.kanade.mangafeed.R; -import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.ui.base.activity.BaseRxActivity; @@ -34,7 +34,7 @@ public class MangaActivity extends BaseRxActivity { @Bind(R.id.view_pager) ViewPager view_pager; @Inject PreferencesHelper preferences; - @Inject ChapterSyncManager chapterSyncManager; + @Inject MangaSyncManager mangaSyncManager; private MangaDetailAdapter adapter; private long manga_id; @@ -116,7 +116,7 @@ public class MangaActivity extends BaseRxActivity { }; pageCount = 2; - if (chapterSyncManager.getMyAnimeList().isLogged()) + if (!is_online && mangaSyncManager.getMyAnimeList().isLogged()) pageCount++; } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListDialogFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListDialogFragment.java index 206398d8a..714ec92c3 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListDialogFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListDialogFragment.java @@ -16,7 +16,7 @@ import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import eu.kanade.mangafeed.R; -import eu.kanade.mangafeed.data.database.models.ChapterSync; +import eu.kanade.mangafeed.data.database.models.MangaSync; import uk.co.ribot.easyadapter.EasyAdapter; import uk.co.ribot.easyadapter.ItemViewHolder; import uk.co.ribot.easyadapter.PositionInfo; @@ -29,60 +29,60 @@ public class MyAnimeListDialogFragment extends DialogFragment { @Bind(R.id.myanimelist_search_button) Button searchButton; @Bind(R.id.myanimelist_search_results) ListView searchResults; - private EasyAdapter adapter; + private EasyAdapter adapter; private MyAnimeListFragment fragment; - private ChapterSync selectedItem; + private MyAnimeListPresenter presenter; + private MangaSync selectedItem; public static MyAnimeListDialogFragment newInstance(MyAnimeListFragment parentFragment) { MyAnimeListDialogFragment dialog = new MyAnimeListDialogFragment(); - dialog.setParentFragment(parentFragment); + dialog.fragment = parentFragment; + dialog.presenter = parentFragment.getPresenter(); return dialog; } @Override public Dialog onCreateDialog(Bundle savedState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - + // Inflate and bind view LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.dialog_myanimelist_search, null); ButterKnife.bind(this, view); - + // Build dialog + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setView(view) .setPositiveButton(R.string.button_ok, (dialog, which) -> onPositiveButtonClick()) .setNegativeButton(R.string.button_cancel, (dialog, which) -> {}); + // Create adapter + adapter = new EasyAdapter<>(getActivity(), ResultViewHolder.class); + searchResults.setAdapter(adapter); + + // Set listeners searchButton.setOnClickListener(v -> - fragment.getPresenter().searchManga(searchText.getText().toString())); + presenter.searchManga(searchText.getText().toString())); searchResults.setOnItemClickListener((parent, viewList, position, id) -> selectedItem = adapter.getItem(position)); - adapter = new EasyAdapter<>(getActivity(), ResultViewHolder.class); - - searchResults.setAdapter(adapter); - + // Do an initial search based on the manga's title + presenter.searchManga(presenter.manga.title); return builder.create(); } private void onPositiveButtonClick() { if (adapter != null && selectedItem != null) { - fragment.getPresenter().registerManga(selectedItem); + presenter.registerManga(selectedItem); } } - public void setResults(List results) { + public void setResults(List results) { selectedItem = null; adapter.setItems(results); } - public void setParentFragment(MyAnimeListFragment fragment) { - this.fragment = fragment; - } - @LayoutId(R.layout.dialog_myanimelist_search_item) - public static class ResultViewHolder extends ItemViewHolder { + public static class ResultViewHolder extends ItemViewHolder { @ViewId(R.id.myanimelist_result_title) TextView title; @@ -91,7 +91,7 @@ public class MyAnimeListDialogFragment extends DialogFragment { } @Override - public void onSetValues(ChapterSync chapter, PositionInfo positionInfo) { + public void onSetValues(MangaSync chapter, PositionInfo positionInfo) { title.setText(chapter.title); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListFragment.java index c2ec9b042..d405e7d8e 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListFragment.java @@ -11,12 +11,13 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; +import java.text.DecimalFormat; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import eu.kanade.mangafeed.R; -import eu.kanade.mangafeed.data.database.models.ChapterSync; +import eu.kanade.mangafeed.data.database.models.MangaSync; import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment; import nucleus.factory.RequiresPresenter; @@ -24,11 +25,15 @@ import nucleus.factory.RequiresPresenter; public class MyAnimeListFragment extends BaseRxFragment { @Bind(R.id.myanimelist_title) TextView title; - @Bind(R.id.myanimelist_last_chapter_read) EditText lastChapterRead; + @Bind(R.id.last_chapter_read) EditText lastChapterRead; + @Bind(R.id.score) TextView score; + @Bind(R.id.status) TextView status; @Bind(R.id.update_button) Button updateButton; private MyAnimeListDialogFragment dialog; + private DecimalFormat decimalFormat = new DecimalFormat("#.##"); + public static MyAnimeListFragment newInstance() { return new MyAnimeListFragment(); } @@ -66,9 +71,11 @@ public class MyAnimeListFragment extends BaseRxFragment { return super.onOptionsItemSelected(item); } - public void setChapterSync(ChapterSync chapterSync) { - title.setText(chapterSync.title); - lastChapterRead.setText(chapterSync.last_chapter_read + ""); + public void setMangaSync(MangaSync mangaSync) { + title.setText(mangaSync.title); + lastChapterRead.setText(mangaSync.last_chapter_read + ""); + score.setText(decimalFormat.format(mangaSync.score)); + status.setText(getPresenter().myAnimeList.getStatus(mangaSync.status)); } private void showSearchDialog() { @@ -78,7 +85,7 @@ public class MyAnimeListFragment extends BaseRxFragment { dialog.show(getActivity().getSupportFragmentManager(), "search"); } - public void onSearchResults(List results) { + public void onSearchResults(List results) { if (dialog != null) dialog.setResults(results); } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListPresenter.java index 45031a77a..85a481e27 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/myanimelist/MyAnimeListPresenter.java @@ -4,13 +4,14 @@ import android.os.Bundle; import javax.inject.Inject; -import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; -import eu.kanade.mangafeed.data.chaptersync.MyAnimeList; +import eu.kanade.mangafeed.data.database.models.MangaSync; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; +import eu.kanade.mangafeed.data.mangasync.services.MyAnimeList; import eu.kanade.mangafeed.data.database.DatabaseHelper; -import eu.kanade.mangafeed.data.database.models.ChapterSync; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import eu.kanade.mangafeed.util.EventBusHook; +import eu.kanade.mangafeed.util.ToastUtil; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; @@ -20,11 +21,11 @@ import timber.log.Timber; public class MyAnimeListPresenter extends BasePresenter { @Inject DatabaseHelper db; - @Inject ChapterSyncManager syncManager; + @Inject MangaSyncManager syncManager; - private MyAnimeList myAnimeList; - private Manga manga; - private ChapterSync chapterSync; + protected MyAnimeList myAnimeList; + protected Manga manga; + private MangaSync mangaSync; private String query; @@ -37,15 +38,19 @@ public class MyAnimeListPresenter extends BasePresenter { protected void onCreate(Bundle savedState) { super.onCreate(savedState); + if (savedState != null) { + onProcessRestart(); + } + myAnimeList = syncManager.getMyAnimeList(); restartableLatestCache(GET_CHAPTER_SYNC, - () -> db.getChapterSync(manga, myAnimeList).createObservable() + () -> db.getMangaSync(manga, myAnimeList).createObservable() .flatMap(Observable::from) - .doOnNext(chapterSync -> this.chapterSync = chapterSync) + .doOnNext(mangaSync -> this.mangaSync = mangaSync) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()), - MyAnimeListFragment::setChapterSync); + MyAnimeListFragment::setMangaSync); restartableLatestCache(GET_SEARCH_RESULTS, () -> myAnimeList.search(query) @@ -59,6 +64,11 @@ public class MyAnimeListPresenter extends BasePresenter { } + private void onProcessRestart() { + stop(GET_CHAPTER_SYNC); + stop(GET_SEARCH_RESULTS); + } + @Override protected void onTakeView(MyAnimeListFragment view) { super.onTakeView(view); @@ -81,10 +91,10 @@ public class MyAnimeListPresenter extends BasePresenter { if (updateSubscription != null) remove(updateSubscription); - chapterSync.last_chapter_read = chapterNumber; + mangaSync.last_chapter_read = chapterNumber; - add(updateSubscription = myAnimeList.update(chapterSync) - .flatMap(response -> db.insertChapterSync(chapterSync).createObservable()) + add(updateSubscription = myAnimeList.update(mangaSync) + .flatMap(response -> db.insertMangaSync(mangaSync).createObservable()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(response -> {}, @@ -99,8 +109,19 @@ public class MyAnimeListPresenter extends BasePresenter { start(GET_SEARCH_RESULTS); } - public void registerManga(ChapterSync selectedManga) { - selectedManga.manga_id = manga.id; - db.insertChapterSync(selectedManga).executeAsBlocking(); + public void registerManga(MangaSync manga) { + manga.manga_id = this.manga.id; + add(myAnimeList.bind(manga) + .flatMap(response -> { + if (response.code() == 200 || response.code() == 201) + return Observable.just(manga); + return Observable.error(new Exception("Could not add manga")); + }) + .flatMap(manga2 -> db.insertMangaSync(manga2).createObservable()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(manga2 -> {}, + error -> ToastUtil.showShort(getContext(), error.getMessage()))); } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java index b1acc15bf..5c747b6b8 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/reader/ReaderPresenter.java @@ -8,12 +8,12 @@ import java.util.List; import javax.inject.Inject; import de.greenrobot.event.EventBus; -import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; -import eu.kanade.mangafeed.data.chaptersync.MyAnimeList; -import eu.kanade.mangafeed.data.chaptersync.UpdateChapterSyncService; +import eu.kanade.mangafeed.data.mangasync.MangaSyncManager; +import eu.kanade.mangafeed.data.mangasync.services.MyAnimeList; +import eu.kanade.mangafeed.data.sync.UpdateMangaSyncService; import eu.kanade.mangafeed.data.database.DatabaseHelper; import eu.kanade.mangafeed.data.database.models.Chapter; -import eu.kanade.mangafeed.data.database.models.ChapterSync; +import eu.kanade.mangafeed.data.database.models.MangaSync; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.download.DownloadManager; import eu.kanade.mangafeed.data.preference.PreferencesHelper; @@ -21,7 +21,7 @@ import eu.kanade.mangafeed.data.source.SourceManager; import eu.kanade.mangafeed.data.source.base.Source; import eu.kanade.mangafeed.data.source.model.Page; import eu.kanade.mangafeed.event.ReaderEvent; -import eu.kanade.mangafeed.event.UpdateChapterSyncEvent; +import eu.kanade.mangafeed.event.UpdateMangaSyncEvent; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import eu.kanade.mangafeed.util.EventBusHook; import icepick.State; @@ -37,7 +37,7 @@ public class ReaderPresenter extends BasePresenter { @Inject PreferencesHelper prefs; @Inject DatabaseHelper db; @Inject DownloadManager downloadManager; - @Inject ChapterSyncManager syncManager; + @Inject MangaSyncManager syncManager; @Inject SourceManager sourceManager; @State Manga manga; @@ -235,7 +235,7 @@ public class ReaderPresenter extends BasePresenter { chapter.last_page_read = currentPage; if (isChapterFinished()) { chapter.read = true; - updateChapterSyncLastChapterRead(); + updateMangaSyncLastChapterRead(); } db.insertChapter(chapter).executeAsBlocking(); } @@ -245,26 +245,26 @@ public class ReaderPresenter extends BasePresenter { return !chapter.read && currentPage == pageList.size() - 1; } - private void updateChapterSyncLastChapterRead() { + private void updateMangaSyncLastChapterRead() { // TODO don't use MAL methods for possible alternatives to MAL MyAnimeList mal = syncManager.getMyAnimeList(); if (!mal.isLogged()) return; - List result = db.getChapterSync(manga, mal).executeAsBlocking(); + List result = db.getMangaSync(manga, mal).executeAsBlocking(); if (result.isEmpty()) return; - ChapterSync chapterSync = result.get(0); + MangaSync mangaSync = result.get(0); int lastChapterReadLocal = (int) Math.floor(chapter.chapter_number); - int lastChapterReadRemote = chapterSync.last_chapter_read; + int lastChapterReadRemote = mangaSync.last_chapter_read; if (lastChapterReadLocal > lastChapterReadRemote) { - chapterSync.last_chapter_read = lastChapterReadLocal; - EventBus.getDefault().postSticky(new UpdateChapterSyncEvent(chapterSync)); - UpdateChapterSyncService.start(getContext()); + mangaSync.last_chapter_read = lastChapterReadLocal; + EventBus.getDefault().postSticky(new UpdateMangaSyncEvent(mangaSync)); + UpdateMangaSyncService.start(getContext()); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsAccountsFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsAccountsFragment.java index eb021022b..7f9063907 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsAccountsFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsAccountsFragment.java @@ -12,18 +12,18 @@ import java.util.List; import javax.inject.Inject; import eu.kanade.mangafeed.App; -import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; -import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; +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.ChapterSyncLoginDialog; +import eu.kanade.mangafeed.ui.setting.preference.MangaSyncLoginDialog; import eu.kanade.mangafeed.ui.setting.preference.SourceLoginDialog; import rx.Observable; public class SettingsAccountsFragment extends SettingsNestedFragment { @Inject SourceManager sourceManager; - @Inject ChapterSyncManager syncManager; + @Inject MangaSyncManager syncManager; public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) { SettingsNestedFragment fragment = new SettingsAccountsFragment(); @@ -56,16 +56,16 @@ public class SettingsAccountsFragment extends SettingsNestedFragment { sourceCategory.addPreference(dialog); } - PreferenceCategory chapterSyncCategory = new PreferenceCategory(screen.getContext()); - chapterSyncCategory.setTitle("Sync"); - screen.addPreference(chapterSyncCategory); + PreferenceCategory mangaSyncCategory = new PreferenceCategory(screen.getContext()); + mangaSyncCategory.setTitle("Sync"); + screen.addPreference(mangaSyncCategory); - for (BaseChapterSync sync : syncManager.getChapterSyncServices()) { - ChapterSyncLoginDialog dialog = new ChapterSyncLoginDialog( + for (BaseMangaSync sync : syncManager.getSyncServices()) { + MangaSyncLoginDialog dialog = new MangaSyncLoginDialog( screen.getContext(), preferences, sync); dialog.setTitle(sync.getName()); - chapterSyncCategory.addPreference(dialog); + mangaSyncCategory.addPreference(dialog); } return view; diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/ChapterSyncLoginDialog.java b/app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/MangaSyncLoginDialog.java similarity index 78% rename from app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/ChapterSyncLoginDialog.java rename to app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/MangaSyncLoginDialog.java index 79eda99a6..15c9b13cf 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/ChapterSyncLoginDialog.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/setting/preference/MangaSyncLoginDialog.java @@ -5,17 +5,17 @@ import android.content.DialogInterface; import android.view.View; import eu.kanade.mangafeed.R; -import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; +import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync; import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.util.ToastUtil; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; -public class ChapterSyncLoginDialog extends LoginDialogPreference { +public class MangaSyncLoginDialog extends LoginDialogPreference { - private BaseChapterSync sync; + private BaseMangaSync sync; - public ChapterSyncLoginDialog(Context context, PreferencesHelper preferences, BaseChapterSync sync) { + public MangaSyncLoginDialog(Context context, PreferencesHelper preferences, BaseMangaSync sync) { super(context, preferences); this.sync = sync; } @@ -26,8 +26,8 @@ public class ChapterSyncLoginDialog extends LoginDialogPreference { title.setText(getContext().getString(R.string.accounts_login_title, sync.getName())); - username.setText(preferences.getChapterSyncUsername(sync)); - password.setText(preferences.getChapterSyncPassword(sync)); + username.setText(preferences.getMangaSyncUsername(sync)); + password.setText(preferences.getMangaSyncPassword(sync)); } @Override @@ -35,7 +35,7 @@ public class ChapterSyncLoginDialog extends LoginDialogPreference { super.onDialogClosed(positiveResult); if (positiveResult) { - preferences.setChapterSyncCredentials(sync, + preferences.setMangaSyncCredentials(sync, username.getText().toString(), password.getText().toString()); } @@ -61,7 +61,7 @@ public class ChapterSyncLoginDialog extends LoginDialogPreference { dialog.dismiss(); ToastUtil.showShort(context, R.string.login_success); } else { - preferences.setChapterSyncCredentials(sync, "", ""); + preferences.setMangaSyncCredentials(sync, "", ""); loginBtn.setProgress(-1); } }, error -> { diff --git a/app/src/main/res/layout/fragment_myanimelist.xml b/app/src/main/res/layout/fragment_myanimelist.xml index d0e0a253f..311a08880 100644 --- a/app/src/main/res/layout/fragment_myanimelist.xml +++ b/app/src/main/res/layout/fragment_myanimelist.xml @@ -35,7 +35,7 @@ android:layout_height="wrap_content" android:inputType="number" android:ems="10" - android:id="@+id/myanimelist_last_chapter_read"/> + android:id="@+id/last_chapter_read"/>