mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Initial MAL support
This commit is contained in:
		| @@ -0,0 +1,16 @@ | ||||
| package eu.kanade.mangafeed.data.chaptersync; | ||||
|  | ||||
| import rx.Observable; | ||||
|  | ||||
| public abstract class BaseChapterSync { | ||||
|  | ||||
|     // Name of the chapter sync service to display | ||||
|     public abstract String getName(); | ||||
|  | ||||
|     // Id of the sync service (must be declared and obtained from ChapterSyncManager to avoid conflicts) | ||||
|     public abstract int getId(); | ||||
|  | ||||
|     public abstract Observable<Boolean> login(String username, String password); | ||||
|  | ||||
|     public abstract boolean isLogged(); | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package eu.kanade.mangafeed.data.chaptersync; | ||||
|  | ||||
| import android.content.Context; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| public class ChapterSyncManager { | ||||
|  | ||||
|     private List<BaseChapterSync> services; | ||||
|     private MyAnimeList myAnimeList; | ||||
|  | ||||
|     public static final int MYANIMELIST = 1; | ||||
|  | ||||
|     public ChapterSyncManager(Context context) { | ||||
|         services = new ArrayList<>(); | ||||
|         myAnimeList = new MyAnimeList(context); | ||||
|         services.add(myAnimeList); | ||||
|     } | ||||
|  | ||||
|     public MyAnimeList getMyAnimeList() { | ||||
|         return myAnimeList; | ||||
|     } | ||||
|  | ||||
|     public List<BaseChapterSync> getChapterSyncServices() { | ||||
|         return services; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,163 @@ | ||||
| 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<Boolean> 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<List<ChapterSync>> 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 = Long.parseLong(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<List<ChapterSync>> 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 = Long.parseLong( | ||||
|                             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<Response> 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; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -16,14 +16,20 @@ 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.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.MangaStorIOSQLitePutResolver; | ||||
| import eu.kanade.mangafeed.data.database.resolvers.MangaWithUnreadGetResolver; | ||||
| import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable; | ||||
| import eu.kanade.mangafeed.data.database.tables.ChapterTable; | ||||
| import eu.kanade.mangafeed.data.database.tables.MangaTable; | ||||
| import eu.kanade.mangafeed.util.ChapterRecognition; | ||||
| @@ -48,6 +54,11 @@ public class DatabaseHelper { | ||||
|                         .getResolver(new ChapterStorIOSQLiteGetResolver()) | ||||
|                         .deleteResolver(new ChapterStorIOSQLiteDeleteResolver()) | ||||
|                         .build()) | ||||
|                 .addTypeMapping(ChapterSync.class, SQLiteTypeMapping.<ChapterSync>builder() | ||||
|                         .putResolver(new ChapterSyncStorIOSQLitePutResolver()) | ||||
|                         .getResolver(new ChapterSyncStorIOSQLiteGetResolver()) | ||||
|                         .deleteResolver(new ChapterSyncStorIOSQLiteDeleteResolver()) | ||||
|                         .build()) | ||||
|                 .build(); | ||||
|     } | ||||
|  | ||||
| @@ -263,4 +274,31 @@ public class DatabaseHelper { | ||||
|                 .objects(chapters) | ||||
|                 .prepare(); | ||||
|     } | ||||
|  | ||||
|     // Chapter sync related queries | ||||
|  | ||||
|     public PreparedGetListOfObjects<ChapterSync> getChapterSync(Manga manga, BaseChapterSync sync) { | ||||
|  | ||||
|         return db.get() | ||||
|                 .listOfObjects(ChapterSync.class) | ||||
|                 .withQuery(Query.builder() | ||||
|                         .table(ChapterSyncTable.TABLE) | ||||
|                         .where(ChapterSyncTable.COLUMN_MANGA_ID + "=? AND " + | ||||
|                                 ChapterSyncTable.COLUMN_SYNC_ID + "=?") | ||||
|                         .whereArgs(manga.id, sync.getId()) | ||||
|                         .build()) | ||||
|                 .prepare(); | ||||
|     } | ||||
|  | ||||
|     public PreparedPutObject<ChapterSync> insertChapterSync(ChapterSync chapter) { | ||||
|         return db.put() | ||||
|                 .object(chapter) | ||||
|                 .prepare(); | ||||
|     } | ||||
|  | ||||
|     public PreparedDeleteObject<ChapterSync> deleteChapterSync(ChapterSync chapter) { | ||||
|         return db.delete() | ||||
|                 .object(chapter) | ||||
|                 .prepare(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,13 +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.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 = 1; | ||||
|     public static final int DATABASE_VERSION = 2; | ||||
|  | ||||
|     public DbOpenHelper(@NonNull Context context) { | ||||
|         super(context, DATABASE_NAME, null, DATABASE_VERSION); | ||||
| @@ -25,7 +26,8 @@ public class DbOpenHelper extends SQLiteOpenHelper { | ||||
|  | ||||
|     @Override | ||||
|     public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { | ||||
|         // no impl | ||||
|         if (oldVersion == 1) | ||||
|             db.execSQL(ChapterSyncTable.getCreateTableQuery()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -0,0 +1,35 @@ | ||||
| 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 long sync_id; | ||||
|  | ||||
|     @StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID) | ||||
|     public long 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package eu.kanade.mangafeed.data.database.tables; | ||||
|  | ||||
| import android.support.annotation.NonNull; | ||||
|  | ||||
| public class ChapterSyncTable { | ||||
|  | ||||
|     public static final String TABLE = "chapter_sync"; | ||||
|  | ||||
|     public static final String COLUMN_ID = "_id"; | ||||
|  | ||||
|     public static final String COLUMN_MANGA_ID = "manga_id"; | ||||
|  | ||||
|     public static final String COLUMN_SYNC_ID = "sync_id"; | ||||
|  | ||||
|     public static final String COLUMN_REMOTE_ID = "remote_id"; | ||||
|  | ||||
|     public static final String COLUMN_TITLE = "title"; | ||||
|  | ||||
|     public static final String COLUMN_LAST_CHAPTER_READ = "last_chapter_read"; | ||||
|  | ||||
|     @NonNull | ||||
|     public static String getCreateTableQuery() { | ||||
|         return "CREATE TABLE " + TABLE + "(" | ||||
|                 + COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY, " | ||||
|                 + COLUMN_MANGA_ID + " INTEGER NOT NULL, " | ||||
|                 + COLUMN_SYNC_ID + " INTEGER NOT NULL, " | ||||
|                 + COLUMN_REMOTE_ID + " INTEGER NOT NULL, " | ||||
|                 + COLUMN_TITLE + " TEXT NOT NULL, " | ||||
|                 + COLUMN_LAST_CHAPTER_READ + " INTEGER NOT NULL, " | ||||
|                 + "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangaTable.TABLE + "(" + MangaTable.COLUMN_ID + ") " | ||||
|                 + "ON DELETE CASCADE" | ||||
|                 + ");"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -8,6 +8,7 @@ import com.f2prateek.rx.preferences.Preference; | ||||
| import com.f2prateek.rx.preferences.RxSharedPreferences; | ||||
|  | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; | ||||
| import eu.kanade.mangafeed.data.source.base.Source; | ||||
| import eu.kanade.mangafeed.util.DiskUtils; | ||||
| import rx.Observable; | ||||
| @@ -20,6 +21,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_"; | ||||
|  | ||||
|     public PreferencesHelper(Context context) { | ||||
|         this.context = context; | ||||
| @@ -84,6 +87,21 @@ public class PreferencesHelper { | ||||
|                 .apply(); | ||||
|     } | ||||
|  | ||||
|     public String getChapterSyncUsername(BaseChapterSync sync) { | ||||
|         return prefs.getString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), ""); | ||||
|     } | ||||
|  | ||||
|     public String getChapterSyncPassword(BaseChapterSync sync) { | ||||
|         return prefs.getString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), ""); | ||||
|     } | ||||
|  | ||||
|     public void setChapterSyncCredentials(BaseChapterSync sync, String username, String password) { | ||||
|         prefs.edit() | ||||
|                 .putString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), username) | ||||
|                 .putString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), password) | ||||
|                 .apply(); | ||||
|     } | ||||
|  | ||||
|     public String getDownloadsDirectory() { | ||||
|         return prefs.getString(getKey(R.string.pref_download_directory_key), | ||||
|                 DiskUtils.getStorageDirectories(context)[0]); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import android.app.Application; | ||||
| import javax.inject.Singleton; | ||||
|  | ||||
| import dagger.Component; | ||||
| import eu.kanade.mangafeed.data.chaptersync.MyAnimeList; | ||||
| import eu.kanade.mangafeed.data.download.DownloadService; | ||||
| import eu.kanade.mangafeed.data.sync.LibraryUpdateService; | ||||
| import eu.kanade.mangafeed.injection.module.AppModule; | ||||
| @@ -12,9 +13,11 @@ import eu.kanade.mangafeed.injection.module.DataModule; | ||||
| import eu.kanade.mangafeed.ui.catalogue.CataloguePresenter; | ||||
| import eu.kanade.mangafeed.ui.download.DownloadPresenter; | ||||
| import eu.kanade.mangafeed.ui.library.LibraryPresenter; | ||||
| import eu.kanade.mangafeed.ui.manga.MangaActivity; | ||||
| import eu.kanade.mangafeed.ui.manga.MangaPresenter; | ||||
| import eu.kanade.mangafeed.ui.manga.chapter.ChaptersPresenter; | ||||
| import eu.kanade.mangafeed.ui.manga.info.MangaInfoPresenter; | ||||
| import eu.kanade.mangafeed.ui.manga.myanimelist.MyAnimeListPresenter; | ||||
| import eu.kanade.mangafeed.ui.reader.ReaderPresenter; | ||||
| import eu.kanade.mangafeed.ui.catalogue.SourcePresenter; | ||||
| import eu.kanade.mangafeed.data.source.base.Source; | ||||
| @@ -39,13 +42,17 @@ public interface AppComponent { | ||||
|     void inject(ChaptersPresenter chaptersPresenter); | ||||
|     void inject(ReaderPresenter readerPresenter); | ||||
|     void inject(DownloadPresenter downloadPresenter); | ||||
|     void inject(MyAnimeListPresenter myAnimeListPresenter); | ||||
|  | ||||
|     void inject(ReaderActivity readerActivity); | ||||
|     void inject(MangaActivity mangaActivity); | ||||
|     void inject(SettingsAccountsFragment settingsAccountsFragment); | ||||
|     void inject(SettingsDownloadsFragment settingsDownloadsFragment); | ||||
|  | ||||
|     void inject(Source source); | ||||
|  | ||||
|     void inject(MyAnimeList myAnimeList); | ||||
|  | ||||
|     void inject(LibraryUpdateService libraryUpdateService); | ||||
|     void inject(DownloadService downloadService); | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import javax.inject.Singleton; | ||||
| import dagger.Module; | ||||
| import dagger.Provides; | ||||
| import eu.kanade.mangafeed.data.cache.CacheManager; | ||||
| import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; | ||||
| import eu.kanade.mangafeed.data.database.DatabaseHelper; | ||||
| import eu.kanade.mangafeed.data.download.DownloadManager; | ||||
| import eu.kanade.mangafeed.data.network.NetworkHelper; | ||||
| @@ -56,4 +57,10 @@ public class DataModule { | ||||
|         return new DownloadManager(app, sourceManager, preferences); | ||||
|     } | ||||
|  | ||||
|     @Provides | ||||
|     @Singleton | ||||
|     ChapterSyncManager provideChapterSyncManager(Application app) { | ||||
|         return new ChapterSyncManager(app); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -11,13 +11,19 @@ import android.support.v4.app.FragmentPagerAdapter; | ||||
| import android.support.v4.view.ViewPager; | ||||
| import android.support.v7.widget.Toolbar; | ||||
|  | ||||
| import javax.inject.Inject; | ||||
|  | ||||
| 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.database.models.Manga; | ||||
| import eu.kanade.mangafeed.data.preference.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.ui.base.activity.BaseRxActivity; | ||||
| import eu.kanade.mangafeed.ui.manga.chapter.ChaptersFragment; | ||||
| import eu.kanade.mangafeed.ui.manga.info.MangaInfoFragment; | ||||
| import eu.kanade.mangafeed.ui.manga.myanimelist.MyAnimeListFragment; | ||||
| import nucleus.factory.RequiresPresenter; | ||||
|  | ||||
| @RequiresPresenter(MangaPresenter.class) | ||||
| @@ -27,6 +33,9 @@ public class MangaActivity extends BaseRxActivity<MangaPresenter> { | ||||
|     @Bind(R.id.tabs) TabLayout tabs; | ||||
|     @Bind(R.id.view_pager) ViewPager view_pager; | ||||
|  | ||||
|     @Inject PreferencesHelper preferences; | ||||
|     @Inject ChapterSyncManager chapterSyncManager; | ||||
|  | ||||
|     private MangaDetailAdapter adapter; | ||||
|     private long manga_id; | ||||
|     private boolean is_online; | ||||
| @@ -43,6 +52,7 @@ public class MangaActivity extends BaseRxActivity<MangaPresenter> { | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         App.get(this).getComponent().inject(this); | ||||
|         setContentView(R.layout.activity_manga_detail); | ||||
|         ButterKnife.bind(this); | ||||
|  | ||||
| @@ -88,25 +98,31 @@ public class MangaActivity extends BaseRxActivity<MangaPresenter> { | ||||
|  | ||||
|     class MangaDetailAdapter extends FragmentPagerAdapter { | ||||
|  | ||||
|         final int PAGE_COUNT = 2; | ||||
|         private String tab_titles[]; | ||||
|         private int pageCount; | ||||
|         private String tabTitles[]; | ||||
|         private Context context; | ||||
|  | ||||
|         final static int INFO_FRAGMENT = 0; | ||||
|         final static int CHAPTERS_FRAGMENT = 1; | ||||
|         final static int MYANIMELIST_FRAGMENT = 2; | ||||
|  | ||||
|         public MangaDetailAdapter(FragmentManager fm, Context context) { | ||||
|             super(fm); | ||||
|             this.context = context; | ||||
|             tab_titles = new String[]{ | ||||
|             tabTitles = new String[]{ | ||||
|                     context.getString(R.string.manga_detail_tab), | ||||
|                     context.getString(R.string.manga_chapters_tab) | ||||
|                     context.getString(R.string.manga_chapters_tab), | ||||
|                     "MAL" | ||||
|             }; | ||||
|  | ||||
|             pageCount = 2; | ||||
|             if (chapterSyncManager.getMyAnimeList().isLogged()) | ||||
|                 pageCount++; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int getCount() { | ||||
|             return PAGE_COUNT; | ||||
|             return pageCount; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
| @@ -116,7 +132,8 @@ public class MangaActivity extends BaseRxActivity<MangaPresenter> { | ||||
|                     return MangaInfoFragment.newInstance(); | ||||
|                 case CHAPTERS_FRAGMENT: | ||||
|                     return ChaptersFragment.newInstance(); | ||||
|  | ||||
|                 case MYANIMELIST_FRAGMENT: | ||||
|                     return MyAnimeListFragment.newInstance(); | ||||
|                 default: | ||||
|                     return null; | ||||
|             } | ||||
| @@ -125,7 +142,7 @@ public class MangaActivity extends BaseRxActivity<MangaPresenter> { | ||||
|         @Override | ||||
|         public CharSequence getPageTitle(int position) { | ||||
|             // Generate title based on item position | ||||
|             return tab_titles[position]; | ||||
|             return tabTitles[position]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,10 +2,6 @@ package eu.kanade.mangafeed.ui.manga.info; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| @@ -52,28 +48,12 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> { | ||||
|         // Inflate the layout for this fragment | ||||
|         View view = inflater.inflate(R.layout.fragment_manga_info, container, false); | ||||
|         ButterKnife.bind(this, view); | ||||
|         favoriteBtn.setOnTouchListener((v, event) -> { | ||||
|             if (event.getAction() == MotionEvent.ACTION_DOWN) { | ||||
|                 getPresenter().toggleFavorite(); | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|             return false; | ||||
|         favoriteBtn.setOnClickListener(v -> { | ||||
|             getPresenter().toggleFavorite(); | ||||
|         }); | ||||
|         getPresenter().initFavoriteText(); | ||||
|  | ||||
|         return view; | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | ||||
|         super.onCreateOptionsMenu(menu, inflater); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     public void setMangaInfo(Manga manga) { | ||||
|   | ||||
| @@ -0,0 +1,99 @@ | ||||
| package eu.kanade.mangafeed.ui.manga.myanimelist; | ||||
|  | ||||
| import android.app.Dialog; | ||||
| import android.os.Bundle; | ||||
| import android.support.v4.app.DialogFragment; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.EditText; | ||||
| import android.widget.ListView; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.database.models.ChapterSync; | ||||
| import uk.co.ribot.easyadapter.EasyAdapter; | ||||
| import uk.co.ribot.easyadapter.ItemViewHolder; | ||||
| import uk.co.ribot.easyadapter.PositionInfo; | ||||
| import uk.co.ribot.easyadapter.annotations.LayoutId; | ||||
| import uk.co.ribot.easyadapter.annotations.ViewId; | ||||
|  | ||||
| public class MyAnimeListDialogFragment extends DialogFragment { | ||||
|  | ||||
|     @Bind(R.id.myanimelist_search_field) EditText searchText; | ||||
|     @Bind(R.id.myanimelist_search_button) Button searchButton; | ||||
|     @Bind(R.id.myanimelist_search_results) ListView searchResults; | ||||
|  | ||||
|     private EasyAdapter<ChapterSync> adapter; | ||||
|     private MyAnimeListFragment fragment; | ||||
|     private ChapterSync selectedItem; | ||||
|  | ||||
|     public static MyAnimeListDialogFragment newInstance(MyAnimeListFragment parentFragment) { | ||||
|         MyAnimeListDialogFragment dialog = new MyAnimeListDialogFragment(); | ||||
|         dialog.setParentFragment(parentFragment); | ||||
|         return dialog; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Dialog onCreateDialog(Bundle savedState) { | ||||
|         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); | ||||
|  | ||||
|         LayoutInflater inflater = getActivity().getLayoutInflater(); | ||||
|  | ||||
|         View view = inflater.inflate(R.layout.dialog_myanimelist_search, null); | ||||
|         ButterKnife.bind(this, view); | ||||
|  | ||||
|  | ||||
|         builder.setView(view) | ||||
|                 .setPositiveButton(R.string.button_ok, (dialog, which) -> onPositiveButtonClick()) | ||||
|                 .setNegativeButton(R.string.button_cancel, (dialog, which) -> {}); | ||||
|  | ||||
|         searchButton.setOnClickListener(v -> | ||||
|                 fragment.getPresenter().searchManga(searchText.getText().toString())); | ||||
|  | ||||
|         searchResults.setOnItemClickListener((parent, viewList, position, id) -> | ||||
|                 selectedItem = adapter.getItem(position)); | ||||
|  | ||||
|         adapter = new EasyAdapter<>(getActivity(), ResultViewHolder.class); | ||||
|  | ||||
|         searchResults.setAdapter(adapter); | ||||
|  | ||||
|         return builder.create(); | ||||
|     } | ||||
|  | ||||
|     private void onPositiveButtonClick() { | ||||
|         if (adapter != null && selectedItem != null) { | ||||
|             fragment.getPresenter().registerManga(selectedItem); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void setResults(List<ChapterSync> 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<ChapterSync> { | ||||
|  | ||||
|         @ViewId(R.id.myanimelist_result_title) TextView title; | ||||
|  | ||||
|         public ResultViewHolder(View view) { | ||||
|             super(view); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onSetValues(ChapterSync chapter, PositionInfo positionInfo) { | ||||
|             title.setText(chapter.title); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,85 @@ | ||||
| package eu.kanade.mangafeed.ui.manga.myanimelist; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.EditText; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| 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.ui.base.fragment.BaseRxFragment; | ||||
| import nucleus.factory.RequiresPresenter; | ||||
|  | ||||
| @RequiresPresenter(MyAnimeListPresenter.class) | ||||
| public class MyAnimeListFragment extends BaseRxFragment<MyAnimeListPresenter> { | ||||
|  | ||||
|     @Bind(R.id.myanimelist_title) TextView title; | ||||
|     @Bind(R.id.myanimelist_last_chapter_read) EditText lastChapterRead; | ||||
|     @Bind(R.id.update_button) Button updateButton; | ||||
|  | ||||
|     private MyAnimeListDialogFragment dialog; | ||||
|  | ||||
|     public static MyAnimeListFragment newInstance() { | ||||
|         return new MyAnimeListFragment(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(Bundle bundle) { | ||||
|         super.onCreate(bundle); | ||||
|         setHasOptionsMenu(true); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | ||||
|         View view = inflater.inflate(R.layout.fragment_myanimelist, container, false); | ||||
|         ButterKnife.bind(this, view); | ||||
|  | ||||
|         updateButton.setOnClickListener(v -> getPresenter().updateLastChapter( | ||||
|                 Integer.parseInt(lastChapterRead.getText().toString()))); | ||||
|  | ||||
|         return view; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | ||||
|         inflater.inflate(R.menu.myanimelist, menu); | ||||
|         super.onCreateOptionsMenu(menu, inflater); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         switch (item.getItemId()) { | ||||
|             case R.id.myanimelist_edit: | ||||
|                 showSearchDialog(); | ||||
|                 return true; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     public void setChapterSync(ChapterSync chapterSync) { | ||||
|         title.setText(chapterSync.title); | ||||
|         lastChapterRead.setText(chapterSync.last_chapter_read + ""); | ||||
|     } | ||||
|  | ||||
|     private void showSearchDialog() { | ||||
|         if (dialog == null) | ||||
|             dialog = MyAnimeListDialogFragment.newInstance(this); | ||||
|  | ||||
|         dialog.show(getActivity().getSupportFragmentManager(), "search"); | ||||
|     } | ||||
|  | ||||
|     public void onSearchResults(List<ChapterSync> results) { | ||||
|         if (dialog != null) | ||||
|             dialog.setResults(results); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,105 @@ | ||||
| package eu.kanade.mangafeed.ui.manga.myanimelist; | ||||
|  | ||||
| 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.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 rx.Observable; | ||||
| import rx.Subscription; | ||||
| import rx.android.schedulers.AndroidSchedulers; | ||||
| import rx.schedulers.Schedulers; | ||||
| import timber.log.Timber; | ||||
|  | ||||
| public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> { | ||||
|  | ||||
|     @Inject DatabaseHelper db; | ||||
|     @Inject ChapterSyncManager syncManager; | ||||
|  | ||||
|     private MyAnimeList myAnimeList; | ||||
|     private Manga manga; | ||||
|     private ChapterSync chapterSync; | ||||
|  | ||||
|     private String query; | ||||
|  | ||||
|     private Subscription updateSubscription; | ||||
|  | ||||
|     private static final int GET_CHAPTER_SYNC = 1; | ||||
|     private static final int GET_SEARCH_RESULTS = 2; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedState) { | ||||
|         super.onCreate(savedState); | ||||
|  | ||||
|         myAnimeList = syncManager.getMyAnimeList(); | ||||
|  | ||||
|         restartableLatestCache(GET_CHAPTER_SYNC, | ||||
|                 () -> db.getChapterSync(manga, myAnimeList).createObservable() | ||||
|                         .flatMap(Observable::from) | ||||
|                         .doOnNext(chapterSync -> this.chapterSync = chapterSync) | ||||
|                         .subscribeOn(Schedulers.io()) | ||||
|                         .observeOn(AndroidSchedulers.mainThread()), | ||||
|                 MyAnimeListFragment::setChapterSync); | ||||
|  | ||||
|         restartableLatestCache(GET_SEARCH_RESULTS, | ||||
|                 () -> myAnimeList.search(query) | ||||
|                         .subscribeOn(Schedulers.io()) | ||||
|                         .observeOn(AndroidSchedulers.mainThread()), | ||||
|                 (view, results) -> { | ||||
|                     view.onSearchResults(results); | ||||
|                 }, (view, error) -> { | ||||
|                     Timber.e(error.getMessage()); | ||||
|                 }); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onTakeView(MyAnimeListFragment view) { | ||||
|         super.onTakeView(view); | ||||
|         registerForStickyEvents(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDropView() { | ||||
|         unregisterForEvents(); | ||||
|         super.onDropView(); | ||||
|     } | ||||
|  | ||||
|     @EventBusHook | ||||
|     public void onEventMainThread(Manga manga) { | ||||
|         this.manga = manga; | ||||
|         start(GET_CHAPTER_SYNC); | ||||
|     } | ||||
|  | ||||
|     public void updateLastChapter(int chapterNumber) { | ||||
|         if (updateSubscription != null) | ||||
|             remove(updateSubscription); | ||||
|  | ||||
|         chapterSync.last_chapter_read = chapterNumber; | ||||
|  | ||||
|         add(updateSubscription = myAnimeList.update(chapterSync) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(response -> {}, | ||||
|                         error -> { | ||||
|                             Timber.e(error.getMessage()); | ||||
|                         } | ||||
|                 )); | ||||
|     } | ||||
|  | ||||
|     public void searchManga(String query) { | ||||
|         this.query = query; | ||||
|         start(GET_SEARCH_RESULTS); | ||||
|     } | ||||
|  | ||||
|     public void registerManga(ChapterSync selectedManga) { | ||||
|         selectedManga.manga_id = manga.id; | ||||
|         db.insertChapterSync(selectedManga).executeAsBlocking(); | ||||
|     } | ||||
| } | ||||
| @@ -1,124 +0,0 @@ | ||||
| package eu.kanade.mangafeed.ui.setting; | ||||
|  | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.os.Bundle; | ||||
| import android.preference.DialogPreference; | ||||
| import android.text.method.PasswordTransformationMethod; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.EditText; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.dd.processbutton.iml.ActionProcessButton; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.preference.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.data.source.base.Source; | ||||
| import eu.kanade.mangafeed.util.ToastUtil; | ||||
| import rx.Subscription; | ||||
| import rx.android.schedulers.AndroidSchedulers; | ||||
| import rx.schedulers.Schedulers; | ||||
|  | ||||
| public class LoginDialogPreference extends DialogPreference { | ||||
|  | ||||
|     @Bind(R.id.accounts_login) TextView title; | ||||
|     @Bind(R.id.username) EditText username; | ||||
|     @Bind(R.id.password) EditText password; | ||||
|     @Bind(R.id.show_password) CheckBox showPassword; | ||||
|     @Bind(R.id.login) ActionProcessButton loginBtn; | ||||
|  | ||||
|     private PreferencesHelper preferences; | ||||
|     private Source source; | ||||
|     private AlertDialog dialog; | ||||
|     private Subscription requestSubscription; | ||||
|     private Context context; | ||||
|  | ||||
|     public LoginDialogPreference(Context context, PreferencesHelper preferences, Source source) { | ||||
|         super(context, null); | ||||
|         this.context = context; | ||||
|         this.preferences = preferences; | ||||
|         this.source = source; | ||||
|  | ||||
|         setDialogLayoutResource(R.layout.pref_account_login); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { | ||||
|         // Hide positive button | ||||
|         builder.setPositiveButton("", this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onBindDialogView(View view) { | ||||
|         ButterKnife.bind(this, view); | ||||
|  | ||||
|         title.setText(getContext().getString(R.string.accounts_login_title, source.getName())); | ||||
|  | ||||
|         username.setText(preferences.getSourceUsername(source)); | ||||
|         password.setText(preferences.getSourcePassword(source)); | ||||
|         showPassword.setOnCheckedChangeListener((buttonView, isChecked) -> { | ||||
|             if (isChecked) | ||||
|                 password.setTransformationMethod(null); | ||||
|             else | ||||
|                 password.setTransformationMethod(new PasswordTransformationMethod()); | ||||
|         }); | ||||
|  | ||||
|         loginBtn.setMode(ActionProcessButton.Mode.ENDLESS); | ||||
|         loginBtn.setOnClickListener(click -> checkLogin()); | ||||
|  | ||||
|         super.onBindDialogView(view); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void showDialog(Bundle state) { | ||||
|         super.showDialog(state); | ||||
|         dialog = ((AlertDialog) getDialog()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDialogClosed(boolean positiveResult) { | ||||
|         if (requestSubscription != null) | ||||
|             requestSubscription.unsubscribe(); | ||||
|  | ||||
|         if(!positiveResult) | ||||
|             return; | ||||
|  | ||||
|         preferences.setSourceCredentials(source, | ||||
|                 username.getText().toString(), | ||||
|                 password.getText().toString()); | ||||
|     } | ||||
|  | ||||
|     private void checkLogin() { | ||||
|         if (requestSubscription != null) | ||||
|             requestSubscription.unsubscribe(); | ||||
|  | ||||
|         if (username.getText().length() == 0 || password.getText().length() == 0) | ||||
|             return; | ||||
|  | ||||
|         loginBtn.setProgress(1); | ||||
|  | ||||
|         requestSubscription = source | ||||
|                 .login(username.getText().toString(), password.getText().toString()) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(logged -> { | ||||
|                     if (logged) { | ||||
|                         // Simulate a positive button click and dismiss the dialog | ||||
|                         onClick(dialog, DialogInterface.BUTTON_POSITIVE); | ||||
|                         dialog.dismiss(); | ||||
|                         ToastUtil.showShort(context, R.string.login_success); | ||||
|                     } else { | ||||
|                         loginBtn.setProgress(-1); | ||||
|                     } | ||||
|                 }, throwable -> { | ||||
|                     loginBtn.setProgress(-1); | ||||
|                     loginBtn.setText(R.string.unknown_error); | ||||
|                 }); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package eu.kanade.mangafeed.ui.setting; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.preference.PreferenceCategory; | ||||
| import android.preference.PreferenceFragment; | ||||
| import android.preference.PreferenceScreen; | ||||
|  | ||||
| @@ -10,16 +11,21 @@ import javax.inject.Inject; | ||||
|  | ||||
| import eu.kanade.mangafeed.App; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync; | ||||
| import eu.kanade.mangafeed.data.chaptersync.ChapterSyncManager; | ||||
| import eu.kanade.mangafeed.data.preference.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.data.source.SourceManager; | ||||
| import eu.kanade.mangafeed.data.source.base.Source; | ||||
| import eu.kanade.mangafeed.ui.base.activity.BaseActivity; | ||||
| import eu.kanade.mangafeed.ui.setting.dialog.ChapterSyncLoginDialog; | ||||
| import eu.kanade.mangafeed.ui.setting.dialog.SourceLoginDialog; | ||||
| import rx.Observable; | ||||
|  | ||||
| public class SettingsAccountsFragment extends PreferenceFragment { | ||||
|  | ||||
|     @Inject SourceManager sourceManager; | ||||
|     @Inject PreferencesHelper preferences; | ||||
|     @Inject SourceManager sourceManager; | ||||
|     @Inject ChapterSyncManager syncManager; | ||||
|  | ||||
|     public static SettingsAccountsFragment newInstance() { | ||||
|         return new SettingsAccountsFragment(); | ||||
| @@ -35,13 +41,30 @@ public class SettingsAccountsFragment extends PreferenceFragment { | ||||
|  | ||||
|         List<Source> sourceAccounts = getSourcesWithLogin(); | ||||
|  | ||||
|         PreferenceCategory sourceCategory = new PreferenceCategory(screen.getContext()); | ||||
|         sourceCategory.setTitle("Sources"); | ||||
|         screen.addPreference(sourceCategory); | ||||
|  | ||||
|         for (Source source : sourceAccounts) { | ||||
|             LoginDialogPreference dialog = new LoginDialogPreference( | ||||
|             SourceLoginDialog dialog = new SourceLoginDialog( | ||||
|                     screen.getContext(), preferences, source); | ||||
|             dialog.setTitle(source.getName()); | ||||
|  | ||||
|             screen.addPreference(dialog); | ||||
|             sourceCategory.addPreference(dialog); | ||||
|         } | ||||
|  | ||||
|         PreferenceCategory chapterSyncCategory = new PreferenceCategory(screen.getContext()); | ||||
|         chapterSyncCategory.setTitle("Sync"); | ||||
|         screen.addPreference(chapterSyncCategory); | ||||
|  | ||||
|         for (BaseChapterSync sync : syncManager.getChapterSyncServices()) { | ||||
|             ChapterSyncLoginDialog dialog = new ChapterSyncLoginDialog( | ||||
|                     screen.getContext(), preferences, sync); | ||||
|             dialog.setTitle(sync.getName()); | ||||
|  | ||||
|             chapterSyncCategory.addPreference(dialog); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -0,0 +1,74 @@ | ||||
| package eu.kanade.mangafeed.ui.setting.dialog; | ||||
|  | ||||
| import android.content.Context; | ||||
| 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.preference.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.util.ToastUtil; | ||||
| import rx.android.schedulers.AndroidSchedulers; | ||||
| import rx.schedulers.Schedulers; | ||||
|  | ||||
| public class ChapterSyncLoginDialog extends LoginDialogPreference { | ||||
|  | ||||
|     private BaseChapterSync sync; | ||||
|  | ||||
|     public ChapterSyncLoginDialog(Context context, PreferencesHelper preferences, BaseChapterSync sync) { | ||||
|         super(context, preferences); | ||||
|         this.sync = sync; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onBindDialogView(View view) { | ||||
|         super.onBindDialogView(view); | ||||
|  | ||||
|         title.setText(getContext().getString(R.string.accounts_login_title, sync.getName())); | ||||
|  | ||||
|         username.setText(preferences.getChapterSyncUsername(sync)); | ||||
|         password.setText(preferences.getChapterSyncPassword(sync)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDialogClosed(boolean positiveResult) { | ||||
|         super.onDialogClosed(positiveResult); | ||||
|  | ||||
|         if (positiveResult) { | ||||
|             preferences.setChapterSyncCredentials(sync, | ||||
|                     username.getText().toString(), | ||||
|                     password.getText().toString()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected void checkLogin() { | ||||
|         if (requestSubscription != null) | ||||
|             requestSubscription.unsubscribe(); | ||||
|  | ||||
|         if (username.getText().length() == 0 || password.getText().length() == 0) | ||||
|             return; | ||||
|  | ||||
|         loginBtn.setProgress(1); | ||||
|  | ||||
|         requestSubscription = sync | ||||
|                 .login(username.getText().toString(), password.getText().toString()) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(logged -> { | ||||
|                     if (logged) { | ||||
|                         // Simulate a positive button click and dismiss the dialog | ||||
|                         onClick(dialog, DialogInterface.BUTTON_POSITIVE); | ||||
|                         dialog.dismiss(); | ||||
|                         ToastUtil.showShort(context, R.string.login_success); | ||||
|                     } else { | ||||
|                         preferences.setChapterSyncCredentials(sync, "", ""); | ||||
|                         loginBtn.setProgress(-1); | ||||
|                     } | ||||
|                 }, error -> { | ||||
|                     loginBtn.setProgress(-1); | ||||
|                     loginBtn.setText(R.string.unknown_error); | ||||
|                 }); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| package eu.kanade.mangafeed.ui.setting.dialog; | ||||
|  | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.preference.DialogPreference; | ||||
| import android.text.method.PasswordTransformationMethod; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.EditText; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.dd.processbutton.iml.ActionProcessButton; | ||||
|  | ||||
| import butterknife.Bind; | ||||
| import butterknife.ButterKnife; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.preference.PreferencesHelper; | ||||
| import rx.Subscription; | ||||
|  | ||||
| public abstract class LoginDialogPreference extends DialogPreference { | ||||
|  | ||||
|     @Bind(R.id.accounts_login) TextView title; | ||||
|     @Bind(R.id.username) EditText username; | ||||
|     @Bind(R.id.password) EditText password; | ||||
|     @Bind(R.id.show_password) CheckBox showPassword; | ||||
|     @Bind(R.id.login) ActionProcessButton loginBtn; | ||||
|  | ||||
|     protected PreferencesHelper preferences; | ||||
|     protected AlertDialog dialog; | ||||
|     protected Subscription requestSubscription; | ||||
|     protected Context context; | ||||
|  | ||||
|     public LoginDialogPreference(Context context, PreferencesHelper preferences) { | ||||
|         super(context, null); | ||||
|         this.context = context; | ||||
|         this.preferences = preferences; | ||||
|  | ||||
|         setDialogLayoutResource(R.layout.pref_account_login); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { | ||||
|         // Hide positive button | ||||
|         builder.setPositiveButton("", this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onBindDialogView(View view) { | ||||
|         super.onBindDialogView(view); | ||||
|         ButterKnife.bind(this, view); | ||||
|  | ||||
|         showPassword.setOnCheckedChangeListener((buttonView, isChecked) -> { | ||||
|             if (isChecked) | ||||
|                 password.setTransformationMethod(null); | ||||
|             else | ||||
|                 password.setTransformationMethod(new PasswordTransformationMethod()); | ||||
|         }); | ||||
|  | ||||
|         loginBtn.setMode(ActionProcessButton.Mode.ENDLESS); | ||||
|         loginBtn.setOnClickListener(click -> checkLogin()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void showDialog(Bundle state) { | ||||
|         super.showDialog(state); | ||||
|         dialog = ((AlertDialog) getDialog()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDialogClosed(boolean positiveResult) { | ||||
|         if (requestSubscription != null) | ||||
|             requestSubscription.unsubscribe(); | ||||
|     } | ||||
|  | ||||
|     protected abstract void checkLogin(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| package eu.kanade.mangafeed.ui.setting.dialog; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.view.View; | ||||
|  | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.preference.PreferencesHelper; | ||||
| import eu.kanade.mangafeed.data.source.base.Source; | ||||
| import eu.kanade.mangafeed.util.ToastUtil; | ||||
| import rx.android.schedulers.AndroidSchedulers; | ||||
| import rx.schedulers.Schedulers; | ||||
|  | ||||
| public class SourceLoginDialog extends LoginDialogPreference { | ||||
|  | ||||
|     private Source source; | ||||
|  | ||||
|     public SourceLoginDialog(Context context, PreferencesHelper preferences, Source source) { | ||||
|         super(context, preferences); | ||||
|         this.source = source; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onBindDialogView(View view) { | ||||
|         super.onBindDialogView(view); | ||||
|  | ||||
|         title.setText(getContext().getString(R.string.accounts_login_title, source.getName())); | ||||
|  | ||||
|         username.setText(preferences.getSourceUsername(source)); | ||||
|         password.setText(preferences.getSourcePassword(source)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDialogClosed(boolean positiveResult) { | ||||
|         super.onDialogClosed(positiveResult); | ||||
|  | ||||
|         if (positiveResult) { | ||||
|             preferences.setSourceCredentials(source, | ||||
|                     username.getText().toString(), | ||||
|                     password.getText().toString()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected void checkLogin() { | ||||
|         if (requestSubscription != null) | ||||
|             requestSubscription.unsubscribe(); | ||||
|  | ||||
|         if (username.getText().length() == 0 || password.getText().length() == 0) | ||||
|             return; | ||||
|  | ||||
|         loginBtn.setProgress(1); | ||||
|  | ||||
|         requestSubscription = source | ||||
|                 .login(username.getText().toString(), password.getText().toString()) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(logged -> { | ||||
|                     if (logged) { | ||||
|                         // Simulate a positive button click and dismiss the dialog | ||||
|                         onClick(dialog, DialogInterface.BUTTON_POSITIVE); | ||||
|                         dialog.dismiss(); | ||||
|                         ToastUtil.showShort(context, R.string.login_success); | ||||
|                     } else { | ||||
|                         preferences.setSourceCredentials(source, "", ""); | ||||
|                         loginBtn.setProgress(-1); | ||||
|                     } | ||||
|                 }, error -> { | ||||
|                     loginBtn.setProgress(-1); | ||||
|                     loginBtn.setText(R.string.unknown_error); | ||||
|                 }); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user