Rename project

This commit is contained in:
inorichi
2016-01-15 15:18:19 +01:00
parent 1508bf42fb
commit 70f4c7fcc3
167 changed files with 647 additions and 654 deletions
@@ -0,0 +1,137 @@
package eu.kanade.tachiyomi.ui.manga;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
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.tachiyomi.App;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager;
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity;
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersFragment;
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoFragment;
import eu.kanade.tachiyomi.ui.manga.myanimelist.MyAnimeListFragment;
import nucleus.factory.RequiresPresenter;
@RequiresPresenter(MangaPresenter.class)
public class MangaActivity extends BaseRxActivity<MangaPresenter> {
@Bind(R.id.toolbar) Toolbar toolbar;
@Bind(R.id.tabs) TabLayout tabs;
@Bind(R.id.view_pager) ViewPager view_pager;
@Inject PreferencesHelper preferences;
@Inject MangaSyncManager mangaSyncManager;
private MangaDetailAdapter adapter;
private long manga_id;
private boolean is_online;
public final static String MANGA_ID = "manga_id";
public final static String MANGA_ONLINE = "manga_online";
public static Intent newIntent(Context context, Manga manga) {
Intent intent = new Intent(context, MangaActivity.class);
intent.putExtra(MANGA_ID, manga.id);
return intent;
}
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
App.get(this).getComponent().inject(this);
setContentView(R.layout.activity_manga);
ButterKnife.bind(this);
setupToolbar(toolbar);
Intent intent = getIntent();
manga_id = intent.getLongExtra(MANGA_ID, -1);
is_online = intent.getBooleanExtra(MANGA_ONLINE, false);
setupViewPager();
if (savedState == null)
getPresenter().queryManga(manga_id);
}
private void setupViewPager() {
adapter = new MangaDetailAdapter(getSupportFragmentManager(), this);
view_pager.setAdapter(adapter);
tabs.setupWithViewPager(view_pager);
if (!is_online)
view_pager.setCurrentItem(MangaDetailAdapter.CHAPTERS_FRAGMENT);
}
public void setManga(Manga manga) {
setToolbarTitle(manga.title);
}
public boolean isCatalogueManga() {
return is_online;
}
class MangaDetailAdapter extends FragmentPagerAdapter {
private int pageCount;
private String tabTitles[];
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);
tabTitles = new String[]{
context.getString(R.string.manga_detail_tab),
context.getString(R.string.manga_chapters_tab),
"MAL"
};
pageCount = 2;
if (!is_online && mangaSyncManager.getMyAnimeList().isLogged())
pageCount++;
}
@Override
public int getCount() {
return pageCount;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case INFO_FRAGMENT:
return MangaInfoFragment.newInstance();
case CHAPTERS_FRAGMENT:
return ChaptersFragment.newInstance();
case MYANIMELIST_FRAGMENT:
return MyAnimeListFragment.newInstance();
default:
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
}
}
@@ -0,0 +1,50 @@
package eu.kanade.tachiyomi.ui.manga;
import android.os.Bundle;
import javax.inject.Inject;
import de.greenrobot.event.EventBus;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import icepick.State;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class MangaPresenter extends BasePresenter<MangaActivity> {
@Inject DatabaseHelper db;
@State long mangaId;
private static final int DB_MANGA = 1;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
restartableLatestCache(DB_MANGA, this::getDbMangaObservable, MangaActivity::setManga);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Avoid new instances receiving wrong manga
EventBus.getDefault().removeStickyEvent(Manga.class);
}
private Observable<Manga> getDbMangaObservable() {
return db.getManga(mangaId).createObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(manga -> EventBus.getDefault().postSticky(manga));
}
public void queryManga(long mangaId) {
this.mangaId = mangaId;
start(DB_MANGA);
}
}
@@ -0,0 +1,55 @@
package eu.kanade.tachiyomi.ui.manga.chapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Chapter;
public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
private ChaptersFragment fragment;
public ChaptersAdapter(ChaptersFragment fragment) {
this.fragment = fragment;
mItems = new ArrayList<>();
setHasStableIds(true);
}
@Override
public void updateDataSet(String param) {}
@Override
public ChaptersHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_chapter, parent, false);
return new ChaptersHolder(v, this, fragment);
}
@Override
public void onBindViewHolder(ChaptersHolder holder, int position) {
final Chapter chapter = getItem(position);
holder.onSetValues(fragment.getActivity(), chapter);
//When user scrolls this bind the correct selection status
holder.itemView.setActivated(isSelected(position));
}
@Override
public long getItemId(int position) {
return mItems.get(position).id;
}
public void setItems(List<Chapter> chapters) {
mItems = chapters;
notifyDataSetChanged();
}
public ChaptersFragment getFragment() {
return fragment;
}
}
@@ -0,0 +1,350 @@
package eu.kanade.tachiyomi.ui.manga.chapter;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Chapter;
import eu.kanade.tachiyomi.data.download.DownloadService;
import eu.kanade.tachiyomi.data.download.model.Download;
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
import eu.kanade.tachiyomi.ui.decoration.DividerItemDecoration;
import eu.kanade.tachiyomi.ui.manga.MangaActivity;
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
import eu.kanade.tachiyomi.util.ToastUtil;
import nucleus.factory.RequiresPresenter;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
@RequiresPresenter(ChaptersPresenter.class)
public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implements
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
@Bind(R.id.chapter_list) RecyclerView recyclerView;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
@Bind(R.id.toolbar_bottom) ViewGroup toolbarBottom;
@Bind(R.id.action_sort) ImageView sortBtn;
@Bind(R.id.action_next_unread) ImageView nextUnreadBtn;
@Bind(R.id.action_show_unread) CheckBox readCb;
@Bind(R.id.action_show_downloaded) CheckBox downloadedCb;
private ChaptersAdapter adapter;
private LinearLayoutManager linearLayout;
private ActionMode actionMode;
private Subscription downloadProgressSubscription;
public static ChaptersFragment newInstance() {
return new ChaptersFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_manga_chapters, container, false);
ButterKnife.bind(this, view);
// Init RecyclerView and adapter
linearLayout = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayout);
recyclerView.addItemDecoration(new DividerItemDecoration(ContextCompat.getDrawable(getContext(), R.drawable.line_divider)));
recyclerView.setHasFixedSize(true);
adapter = new ChaptersAdapter(this);
recyclerView.setAdapter(adapter);
// Set initial values
setReadFilter();
setDownloadedFilter();
setSortIcon();
// Init listeners
swipeRefresh.setOnRefreshListener(this::fetchChapters);
readCb.setOnCheckedChangeListener((arg, isChecked) ->
getPresenter().setReadFilter(isChecked));
downloadedCb.setOnCheckedChangeListener((v, isChecked) ->
getPresenter().setDownloadedFilter(isChecked));
sortBtn.setOnClickListener(v -> {
getPresenter().revertSortOrder();
setSortIcon();
});
nextUnreadBtn.setOnClickListener(v -> {
Chapter chapter = getPresenter().getNextUnreadChapter();
if (chapter != null) {
openChapter(chapter);
} else {
ToastUtil.showShort(getContext(), R.string.no_next_chapter);
}
});
return view;
}
@Override
public void onResume() {
super.onResume();
observeChapterDownloadProgress();
}
@Override
public void onPause() {
unsubscribeChapterDownloadProgress();
super.onPause();
}
public void onNextChapters(List<Chapter> chapters) {
// If the list is empty, fetch chapters from source if the conditions are met
// We use presenter chapters instead because they are always unfiltered
if (getPresenter().getChapters().isEmpty())
initialFetchChapters();
destroyActionModeIfNeeded();
adapter.setItems(chapters);
}
private void initialFetchChapters() {
// Only fetch if this view is from the catalog and it hasn't requested previously
if (isCatalogueManga() && !getPresenter().hasRequested()) {
fetchChapters();
}
}
public void fetchChapters() {
if (getPresenter().getManga() != null) {
swipeRefresh.setRefreshing(true);
getPresenter().fetchChaptersFromSource();
}
}
public void onFetchChaptersDone() {
swipeRefresh.setRefreshing(false);
}
public void onFetchChaptersError() {
swipeRefresh.setRefreshing(false);
ToastUtil.showShort(getContext(), R.string.fetch_chapters_error);
}
public boolean isCatalogueManga() {
return ((MangaActivity) getActivity()).isCatalogueManga();
}
protected void openChapter(Chapter chapter) {
getPresenter().onOpenChapter(chapter);
Intent intent = ReaderActivity.newIntent(getActivity());
startActivity(intent);
}
private void observeChapterDownloadProgress() {
downloadProgressSubscription = getPresenter().getDownloadProgressObs()
.subscribe(this::onDownloadProgressChange,
error -> { /* TODO getting a NPE sometimes on 'manga' from presenter */ });
}
private void unsubscribeChapterDownloadProgress() {
if (downloadProgressSubscription != null)
downloadProgressSubscription.unsubscribe();
}
private void onDownloadProgressChange(Download download) {
ChaptersHolder holder = getHolder(download.chapter);
if (holder != null)
holder.onProgressChange(getContext(), download.downloadedImages, download.pages.size());
}
public void onChapterStatusChange(Chapter chapter) {
ChaptersHolder holder = getHolder(chapter);
if (holder != null)
holder.onStatusChange(chapter.status);
}
@Nullable
private ChaptersHolder getHolder(Chapter chapter) {
return (ChaptersHolder) recyclerView.findViewHolderForItemId(chapter.id);
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.chapter_selection, menu);
adapter.setMode(ChaptersAdapter.MODE_MULTI);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_select_all:
return onSelectAll();
case R.id.action_mark_as_read:
return onMarkAsRead(getSelectedChapters());
case R.id.action_mark_as_unread:
return onMarkAsUnread(getSelectedChapters());
case R.id.action_download:
return onDownload(getSelectedChapters());
case R.id.action_delete:
return onDelete(getSelectedChapters());
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
adapter.setMode(ChaptersAdapter.MODE_SINGLE);
adapter.clearSelection();
actionMode = null;
}
private Observable<Chapter> getSelectedChapters() {
// Create a blocking copy of the selected chapters.
// When the action mode is closed the list is cleared. If we use background
// threads with this observable, some emissions could be lost.
List<Chapter> chapters = Observable.from(adapter.getSelectedItems())
.map(adapter::getItem).toList().toBlocking().single();
return Observable.from(chapters);
}
public void destroyActionModeIfNeeded() {
if (actionMode != null) {
actionMode.finish();
}
}
protected boolean onSelectAll() {
adapter.selectAll();
setContextTitle(adapter.getSelectedItemCount());
return true;
}
protected boolean onMarkAsRead(Observable<Chapter> chapters) {
getPresenter().markChaptersRead(chapters, true);
return true;
}
protected boolean onMarkAsUnread(Observable<Chapter> chapters) {
getPresenter().markChaptersRead(chapters, false);
return true;
}
protected boolean onDownload(Observable<Chapter> chapters) {
DownloadService.start(getActivity());
Observable<Chapter> observable = chapters
.doOnCompleted(adapter::notifyDataSetChanged);
getPresenter().downloadChapters(observable);
destroyActionModeIfNeeded();
return true;
}
protected boolean onDelete(Observable<Chapter> chapters) {
int size = adapter.getSelectedItemCount();
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.deleting)
.progress(false, size, true)
.cancelable(false)
.show();
Observable<Chapter> observable = chapters
.concatMap(chapter -> {
getPresenter().deleteChapter(chapter);
return Observable.just(chapter);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(chapter -> {
dialog.incrementProgress(1);
chapter.status = Download.NOT_DOWNLOADED;
})
.doOnCompleted(adapter::notifyDataSetChanged)
.finallyDo(dialog::dismiss);
getPresenter().deleteChapters(observable);
destroyActionModeIfNeeded();
return true;
}
@Override
public boolean onListItemClick(int position) {
if (actionMode != null && adapter.getMode() == ChaptersAdapter.MODE_MULTI) {
toggleSelection(position);
return true;
} else {
openChapter(adapter.getItem(position));
return false;
}
}
@Override
public void onListItemLongClick(int position) {
if (actionMode == null)
actionMode = getBaseActivity().startSupportActionMode(this);
toggleSelection(position);
}
private void toggleSelection(int position) {
adapter.toggleSelection(position, false);
int count = adapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
setContextTitle(count);
actionMode.invalidate();
}
}
private void setContextTitle(int count) {
actionMode.setTitle(getString(R.string.label_selected, count));
}
public void setSortIcon() {
if (sortBtn != null) {
boolean aToZ = getPresenter().getSortOrder();
sortBtn.setImageResource(!aToZ ? R.drawable.ic_expand_less_white_36dp : R.drawable.ic_expand_more_white_36dp);
}
}
public void setReadFilter() {
if (readCb != null) {
readCb.setChecked(getPresenter().getReadFilter());
}
}
public void setDownloadedFilter() {
if (downloadedCb != null) {
downloadedCb.setChecked(getPresenter().getDownloadedFilter());
}
}
}
@@ -0,0 +1,110 @@
package eu.kanade.tachiyomi.ui.manga.chapter;
import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Chapter;
import eu.kanade.tachiyomi.data.download.model.Download;
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
import rx.Observable;
public class ChaptersHolder extends FlexibleViewHolder {
private final ChaptersAdapter adapter;
private Chapter item;
@Bind(R.id.chapter_title) TextView title;
@Bind(R.id.download_text) TextView downloadText;
@Bind(R.id.chapter_menu) RelativeLayout chapterMenu;
@Bind(R.id.chapter_pages) TextView pages;
@Bind(R.id.chapter_date) TextView date;
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
public ChaptersHolder(View view, ChaptersAdapter adapter, OnListItemClickListener listener) {
super(view, adapter, listener);
this.adapter = adapter;
ButterKnife.bind(this, view);
chapterMenu.setOnClickListener(v -> v.post(() -> showPopupMenu(v)));
}
public void onSetValues(Context context, Chapter chapter) {
this.item = chapter;
title.setText(chapter.name);
if (chapter.read) {
title.setTextColor(ContextCompat.getColor(context, R.color.hint_text));
} else {
title.setTextColor(ContextCompat.getColor(context, R.color.primary_text));
}
if (!chapter.read && chapter.last_page_read > 0) {
pages.setText(context.getString(R.string.chapter_progress, chapter.last_page_read + 1));
} else {
pages.setText("");
}
onStatusChange(chapter.status);
date.setText(sdf.format(new Date(chapter.date_upload)));
}
public void onStatusChange(int status) {
switch (status) {
case Download.QUEUE:
downloadText.setText(R.string.chapter_queued); break;
case Download.DOWNLOADING:
downloadText.setText(R.string.chapter_downloading); break;
case Download.DOWNLOADED:
downloadText.setText(R.string.chapter_downloaded); break;
case Download.ERROR:
downloadText.setText(R.string.chapter_error); break;
default:
downloadText.setText(""); break;
}
}
public void onProgressChange(Context context, int downloaded, int total) {
downloadText.setText(context.getString(
R.string.chapter_downloading_progress, downloaded, total));
}
private void showPopupMenu(View view) {
// Create a PopupMenu, giving it the clicked view for an anchor
PopupMenu popup = new PopupMenu(adapter.getFragment().getActivity(), view);
// Inflate our menu resource into the PopupMenu's Menu
popup.getMenuInflater().inflate(R.menu.chapter_single, popup.getMenu());
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener(menuItem -> {
Observable<Chapter> chapter = Observable.just(item);
switch (menuItem.getItemId()) {
case R.id.action_mark_as_read:
return adapter.getFragment().onMarkAsRead(chapter);
case R.id.action_mark_as_unread:
return adapter.getFragment().onMarkAsUnread(chapter);
case R.id.action_download:
return adapter.getFragment().onDownload(chapter);
case R.id.action_delete:
return adapter.getFragment().onDelete(chapter);
}
return false;
});
// Finally show the PopupMenu
popup.show();
}
}
@@ -0,0 +1,275 @@
package eu.kanade.tachiyomi.ui.manga.chapter;
import android.os.Bundle;
import android.util.Pair;
import java.util.List;
import javax.inject.Inject;
import de.greenrobot.event.EventBus;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.data.database.models.Chapter;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.download.DownloadManager;
import eu.kanade.tachiyomi.data.download.model.Download;
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
import eu.kanade.tachiyomi.data.source.SourceManager;
import eu.kanade.tachiyomi.data.source.base.Source;
import eu.kanade.tachiyomi.event.ChapterCountEvent;
import eu.kanade.tachiyomi.event.DownloadChaptersEvent;
import eu.kanade.tachiyomi.event.ReaderEvent;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import eu.kanade.tachiyomi.util.EventBusHook;
import icepick.State;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subjects.PublishSubject;
import timber.log.Timber;
public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
@Inject DatabaseHelper db;
@Inject SourceManager sourceManager;
@Inject PreferencesHelper preferences;
@Inject DownloadManager downloadManager;
private Manga manga;
private Source source;
private List<Chapter> chapters;
private boolean sortOrderAToZ = true;
private boolean onlyUnread = true;
private boolean onlyDownloaded;
@State boolean hasRequested;
private PublishSubject<List<Chapter>> chaptersSubject;
private static final int DB_CHAPTERS = 1;
private static final int FETCH_CHAPTERS = 2;
private static final int CHAPTER_STATUS_CHANGES = 3;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState != null) {
onProcessRestart();
}
chaptersSubject = PublishSubject.create();
restartableLatestCache(DB_CHAPTERS,
this::getDbChaptersObs,
ChaptersFragment::onNextChapters);
restartableFirst(FETCH_CHAPTERS,
this::getOnlineChaptersObs,
(view, result) -> view.onFetchChaptersDone(),
(view, error) -> view.onFetchChaptersError());
restartableLatestCache(CHAPTER_STATUS_CHANGES,
this::getChapterStatusObs,
(view, download) -> view.onChapterStatusChange(download.chapter),
(view, error) -> Timber.e(error.getCause(), error.getMessage()));
registerForStickyEvents();
}
private void onProcessRestart() {
stop(DB_CHAPTERS);
stop(FETCH_CHAPTERS);
stop(CHAPTER_STATUS_CHANGES);
}
@Override
protected void onDestroy() {
unregisterForEvents();
EventBus.getDefault().removeStickyEvent(ChapterCountEvent.class);
super.onDestroy();
}
@EventBusHook
public void onEventMainThread(Manga manga) {
this.manga = manga;
if (!isSubscribed(DB_CHAPTERS)) {
source = sourceManager.get(manga.source);
start(DB_CHAPTERS);
add(db.getChapters(manga).createObservable()
.subscribeOn(Schedulers.io())
.doOnNext(chapters -> {
this.chapters = chapters;
EventBus.getDefault().postSticky(new ChapterCountEvent(chapters.size()));
for (Chapter chapter : chapters) {
setChapterStatus(chapter);
}
start(CHAPTER_STATUS_CHANGES);
})
.subscribe(chaptersSubject::onNext));
}
}
public void fetchChaptersFromSource() {
hasRequested = true;
start(FETCH_CHAPTERS);
}
private void refreshChapters() {
chaptersSubject.onNext(chapters);
}
private Observable<Pair<Integer, Integer>> getOnlineChaptersObs() {
return source.pullChaptersFromNetwork(manga.url)
.subscribeOn(Schedulers.io())
.flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters))
.observeOn(AndroidSchedulers.mainThread());
}
private Observable<List<Chapter>> getDbChaptersObs() {
return chaptersSubject.flatMap(this::applyChapterFilters)
.observeOn(AndroidSchedulers.mainThread());
}
private Observable<List<Chapter>> applyChapterFilters(List<Chapter> chapters) {
Observable<Chapter> observable = Observable.from(chapters)
.subscribeOn(Schedulers.io());
if (onlyUnread) {
observable = observable.filter(chapter -> !chapter.read);
}
if (onlyDownloaded) {
observable = observable.filter(chapter -> chapter.status == Download.DOWNLOADED);
}
return observable.toSortedList((chapter, chapter2) -> sortOrderAToZ ?
Float.compare(chapter2.chapter_number, chapter.chapter_number) :
Float.compare(chapter.chapter_number, chapter2.chapter_number));
}
private void setChapterStatus(Chapter chapter) {
for (Download download : downloadManager.getQueue()) {
if (chapter.id.equals(download.chapter.id)) {
chapter.status = download.getStatus();
return;
}
}
if (downloadManager.isChapterDownloaded(source, manga, chapter)) {
chapter.status = Download.DOWNLOADED;
} else {
chapter.status = Download.NOT_DOWNLOADED;
}
}
private Observable<Download> getChapterStatusObs() {
return downloadManager.getQueue().getStatusObservable()
.observeOn(AndroidSchedulers.mainThread())
.filter(download -> download.manga.id.equals(manga.id))
.doOnNext(this::updateChapterStatus);
}
public void updateChapterStatus(Download download) {
for (Chapter chapter : chapters) {
if (download.chapter.id.equals(chapter.id)) {
chapter.status = download.getStatus();
break;
}
}
if (onlyDownloaded && download.getStatus() == Download.DOWNLOADED)
refreshChapters();
}
public Observable<Download> getDownloadProgressObs() {
return downloadManager.getQueue().getProgressObservable()
.filter(download -> download.manga.id.equals(manga.id))
.observeOn(AndroidSchedulers.mainThread());
}
public void onOpenChapter(Chapter chapter) {
EventBus.getDefault().postSticky(new ReaderEvent(source, manga, chapter));
}
public Chapter getNextUnreadChapter() {
return db.getNextUnreadChapter(manga).executeAsBlocking();
}
public void markChaptersRead(Observable<Chapter> selectedChapters, boolean read) {
add(selectedChapters
.subscribeOn(Schedulers.io())
.map(chapter -> {
chapter.read = read;
if (!read) chapter.last_page_read = 0;
return chapter;
})
.toList()
.flatMap(chapters -> db.insertChapters(chapters).createObservable())
.observeOn(AndroidSchedulers.mainThread())
.subscribe());
}
public void downloadChapters(Observable<Chapter> selectedChapters) {
add(selectedChapters
.toList()
.subscribe(chapters -> {
EventBus.getDefault().postSticky(new DownloadChaptersEvent(manga, chapters));
}));
}
public void deleteChapters(Observable<Chapter> selectedChapters) {
add(selectedChapters
.subscribe(chapter -> {
downloadManager.getQueue().remove(chapter);
}, error -> {
Timber.e(error.getMessage());
}, () -> {
if (onlyDownloaded)
refreshChapters();
}));
}
public void deleteChapter(Chapter chapter) {
downloadManager.deleteChapter(source, manga, chapter);
}
public void revertSortOrder() {
//TODO manga.chapter_order
sortOrderAToZ = !sortOrderAToZ;
refreshChapters();
}
public void setReadFilter(boolean onlyUnread) {
//TODO do we need save filter for manga?
this.onlyUnread = onlyUnread;
refreshChapters();
}
public void setDownloadedFilter(boolean onlyDownloaded) {
this.onlyDownloaded = onlyDownloaded;
refreshChapters();
}
public boolean getSortOrder() {
return sortOrderAToZ;
}
public boolean getReadFilter() {
return onlyUnread;
}
public boolean getDownloadedFilter() {
return onlyDownloaded;
}
public Manga getManga() {
return manga;
}
public List<Chapter> getChapters() {
return chapters;
}
public boolean hasRequested() {
return hasRequested;
}
}
@@ -0,0 +1,116 @@
package eu.kanade.tachiyomi.ui.manga.info;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.load.model.LazyHeaders;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.cache.CoverCache;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
import nucleus.factory.RequiresPresenter;
@RequiresPresenter(MangaInfoPresenter.class)
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
@Bind(R.id.manga_artist) TextView artist;
@Bind(R.id.manga_author) TextView author;
@Bind(R.id.manga_chapters) TextView chapterCount;
@Bind(R.id.manga_genres) TextView genres;
@Bind(R.id.manga_status) TextView status;
@Bind(R.id.manga_summary) TextView description;
@Bind(R.id.manga_cover) ImageView cover;
@Bind(R.id.action_favorite) Button favoriteBtn;
public static MangaInfoFragment newInstance() {
return new MangaInfoFragment();
}
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_manga_info, container, false);
ButterKnife.bind(this, view);
favoriteBtn.setOnClickListener(v -> {
getPresenter().toggleFavorite();
});
swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
return view;
}
public void onNextManga(Manga manga) {
if (manga.initialized) {
setMangaInfo(manga);
} else {
// Initialize manga
fetchMangaFromSource();
}
}
private void setMangaInfo(Manga manga) {
artist.setText(manga.artist);
author.setText(manga.author);
genres.setText(manga.genre);
status.setText(manga.getStatus(getActivity()));
description.setText(manga.description);
setFavoriteText(manga.favorite);
CoverCache coverCache = getPresenter().coverCache;
LazyHeaders headers = getPresenter().source.getGlideHeaders();
if (manga.thumbnail_url != null && cover.getDrawable() == null) {
if (manga.favorite) {
coverCache.saveAndLoadFromCache(cover, manga.thumbnail_url, headers);
} else {
coverCache.loadFromNetwork(cover, manga.thumbnail_url, headers);
}
}
}
public void setChapterCount(int count) {
chapterCount.setText(String.valueOf(count));
}
public void setFavoriteText(boolean isFavorite) {
favoriteBtn.setText(!isFavorite ? R.string.add_to_library : R.string.remove_from_library);
}
private void fetchMangaFromSource() {
setRefreshing(true);
getPresenter().fetchMangaFromSource();
}
public void onFetchMangaDone() {
setRefreshing(false);
}
public void onFetchMangaError() {
setRefreshing(false);
}
private void setRefreshing(boolean value) {
swipeRefresh.setRefreshing(value);
}
}
@@ -0,0 +1,119 @@
package eu.kanade.tachiyomi.ui.manga.info;
import android.os.Bundle;
import javax.inject.Inject;
import eu.kanade.tachiyomi.data.cache.CoverCache;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.source.SourceManager;
import eu.kanade.tachiyomi.data.source.base.Source;
import eu.kanade.tachiyomi.event.ChapterCountEvent;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import eu.kanade.tachiyomi.util.EventBusHook;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
@Inject DatabaseHelper db;
@Inject SourceManager sourceManager;
@Inject CoverCache coverCache;
private Manga manga;
protected Source source;
private int count = -1;
private boolean isFetching;
private static final int GET_MANGA = 1;
private static final int GET_CHAPTER_COUNT = 2;
private static final int FETCH_MANGA_INFO = 3;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState != null) {
onProcessRestart();
}
restartableLatestCache(GET_MANGA,
() -> Observable.just(manga),
MangaInfoFragment::onNextManga);
restartableLatestCache(GET_CHAPTER_COUNT,
() -> Observable.just(count),
MangaInfoFragment::setChapterCount);
restartableFirst(FETCH_MANGA_INFO,
this::fetchMangaObs,
(view, manga) -> view.onFetchMangaDone(),
(view, error) -> view.onFetchMangaError());
registerForStickyEvents();
}
private void onProcessRestart() {
stop(GET_MANGA);
stop(GET_CHAPTER_COUNT);
stop(FETCH_MANGA_INFO);
}
@Override
protected void onDestroy() {
unregisterForEvents();
super.onDestroy();
}
@EventBusHook
public void onEventMainThread(Manga manga) {
this.manga = manga;
source = sourceManager.get(manga.source);
start(GET_MANGA);
}
@EventBusHook
public void onEventMainThread(ChapterCountEvent event) {
if (count != event.getCount()) {
count = event.getCount();
start(GET_CHAPTER_COUNT);
}
}
public void fetchMangaFromSource() {
if (!isFetching) {
isFetching = true;
start(FETCH_MANGA_INFO);
}
}
private Observable<Manga> fetchMangaObs() {
return source.pullMangaFromNetwork(manga.url)
.flatMap(networkManga -> {
manga.copyFrom(networkManga);
db.insertManga(manga).executeAsBlocking();
return Observable.just(manga);
})
.finallyDo(() -> isFetching = false)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public void toggleFavorite() {
manga.favorite = !manga.favorite;
onMangaFavoriteChange(manga.favorite);
db.insertManga(manga).executeAsBlocking();
}
private void onMangaFavoriteChange(boolean isFavorite) {
if (isFavorite) {
coverCache.save(manga.thumbnail_url, source.getGlideHeaders());
} else {
coverCache.delete(manga.thumbnail_url);
}
}
}
@@ -0,0 +1,172 @@
package eu.kanade.tachiyomi.ui.manga.myanimelist;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.util.List;
import java.util.concurrent.TimeUnit;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.MangaSync;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.subjects.PublishSubject;
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_results) ListView searchResults;
@Bind(R.id.progress) ProgressBar progressBar;
private EasyAdapter<MangaSync> adapter;
private MangaSync selectedItem;
private Subscription searchSubscription;
public static MyAnimeListDialogFragment newInstance() {
return new MyAnimeListDialogFragment();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedState) {
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.customView(R.layout.dialog_myanimelist_search, false)
.positiveText(R.string.button_ok)
.negativeText(R.string.button_cancel)
.onPositive((dialog1, which) -> onPositiveButtonClick())
.build();
ButterKnife.bind(this, dialog.getView());
// Create adapter
adapter = new EasyAdapter<>(getActivity(), ResultViewHolder.class);
searchResults.setAdapter(adapter);
// Set listeners
searchResults.setOnItemClickListener((parent, viewList, position, id) ->
selectedItem = adapter.getItem(position));
// Do an initial search based on the manga's title
if (savedState == null) {
String title = getPresenter().manga.title;
searchText.append(title);
search(title);
}
return dialog;
}
@Override
public void onResume() {
super.onResume();
PublishSubject<String> querySubject = PublishSubject.create();
searchText.addTextChangedListener(new SimpleTextChangeListener() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
querySubject.onNext(s.toString());
}
});
// Listen to text changes
searchSubscription = querySubject.debounce(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::search);
}
@Override
public void onPause() {
if (searchSubscription != null) {
searchSubscription.unsubscribe();
}
super.onPause();
}
private void onPositiveButtonClick() {
if (adapter != null && selectedItem != null) {
getPresenter().registerManga(selectedItem);
}
}
private void search(String query) {
if (!TextUtils.isEmpty(query)) {
searchResults.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
getPresenter().searchManga(query);
}
}
public void onSearchResults(List<MangaSync> results) {
selectedItem = null;
progressBar.setVisibility(View.GONE);
searchResults.setVisibility(View.VISIBLE);
adapter.setItems(results);
}
public void onSearchResultsError() {
progressBar.setVisibility(View.GONE);
searchResults.setVisibility(View.VISIBLE);
adapter.getItems().clear();
}
public MyAnimeListFragment getMALFragment() {
return (MyAnimeListFragment) getParentFragment();
}
public MyAnimeListPresenter getPresenter() {
return getMALFragment().getPresenter();
}
@LayoutId(R.layout.dialog_myanimelist_search_item)
public static class ResultViewHolder extends ItemViewHolder<MangaSync> {
@ViewId(R.id.myanimelist_result_title) TextView title;
public ResultViewHolder(View view) {
super(view);
}
@Override
public void onSetValues(MangaSync chapter, PositionInfo positionInfo) {
title.setText(chapter.title);
}
}
private static class SimpleTextChangeListener implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
}
@@ -0,0 +1,181 @@
package eu.kanade.tachiyomi.ui.manga.myanimelist;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.NumberPicker;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.text.DecimalFormat;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.MangaSync;
import eu.kanade.tachiyomi.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_chapters) TextView chapters;
@Bind(R.id.myanimelist_score) TextView score;
@Bind(R.id.myanimelist_status) TextView status;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
private MyAnimeListDialogFragment dialog;
private DecimalFormat decimalFormat = new DecimalFormat("#.##");
private final static String SEARCH_FRAGMENT_TAG = "mal_search";
public static MyAnimeListFragment newInstance() {
return new MyAnimeListFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_myanimelist, container, false);
ButterKnife.bind(this, view);
swipeRefresh.setEnabled(false);
swipeRefresh.setOnRefreshListener(() -> getPresenter().refresh());
return view;
}
public void setMangaSync(MangaSync mangaSync) {
swipeRefresh.setEnabled(mangaSync != null);
if (mangaSync != null) {
title.setText(mangaSync.title);
chapters.setText(mangaSync.last_chapter_read + "/" +
(mangaSync.total_chapters > 0 ? mangaSync.total_chapters : "-"));
score.setText(mangaSync.score == 0 ? "-" : decimalFormat.format(mangaSync.score));
status.setText(getPresenter().myAnimeList.getStatus(mangaSync.status));
}
}
public void onRefreshDone() {
swipeRefresh.setRefreshing(false);
}
public void onRefreshError() {
swipeRefresh.setRefreshing(false);
}
public void setSearchResults(List<MangaSync> results) {
findSearchFragmentIfNeeded();
if (dialog != null) {
dialog.onSearchResults(results);
}
}
public void setSearchResultsError() {
findSearchFragmentIfNeeded();
if (dialog != null) {
dialog.onSearchResultsError();
}
}
private void findSearchFragmentIfNeeded() {
if (dialog == null) {
dialog = (MyAnimeListDialogFragment) getChildFragmentManager()
.findFragmentByTag(SEARCH_FRAGMENT_TAG);
}
}
@OnClick(R.id.myanimelist_title_layout)
void onTitleClick() {
if (dialog == null)
dialog = MyAnimeListDialogFragment.newInstance();
getPresenter().restartSearch();
dialog.show(getChildFragmentManager(), SEARCH_FRAGMENT_TAG);
}
@OnClick(R.id.myanimelist_status_layout)
void onStatusClick() {
if (getPresenter().mangaSync == null)
return;
Context ctx = getActivity();
new MaterialDialog.Builder(ctx)
.title(R.string.status)
.items(getPresenter().getAllStatus(ctx))
.itemsCallbackSingleChoice(getPresenter().getIndexFromStatus(),
(materialDialog, view, i, charSequence) -> {
getPresenter().setStatus(i);
status.setText("...");
return true;
})
.show();
}
@OnClick(R.id.myanimelist_chapters_layout)
void onChaptersClick() {
if (getPresenter().mangaSync == null)
return;
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.chapters)
.customView(R.layout.dialog_myanimelist_chapters, false)
.positiveText(R.string.button_ok)
.negativeText(R.string.button_cancel)
.onPositive((materialDialog, dialogAction) -> {
View view = materialDialog.getCustomView();
if (view != null) {
NumberPicker np = (NumberPicker) view.findViewById(R.id.chapters_picker);
getPresenter().setLastChapterRead(np.getValue());
chapters.setText("...");
}
})
.show();
View view = dialog.getCustomView();
if (view != null) {
NumberPicker np = (NumberPicker) view.findViewById(R.id.chapters_picker);
// Set initial value
np.setValue(getPresenter().mangaSync.last_chapter_read);
// Don't allow to go from 0 to 9999
np.setWrapSelectorWheel(false);
}
}
@OnClick(R.id.myanimelist_score_layout)
void onScoreClick() {
if (getPresenter().mangaSync == null)
return;
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.score)
.customView(R.layout.dialog_myanimelist_score, false)
.positiveText(R.string.button_ok)
.negativeText(R.string.button_cancel)
.onPositive((materialDialog, dialogAction) -> {
View view = materialDialog.getCustomView();
if (view != null) {
NumberPicker np = (NumberPicker) view.findViewById(R.id.score_picker);
getPresenter().setScore(np.getValue());
score.setText("...");
}
})
.show();
View view = dialog.getCustomView();
if (view != null) {
NumberPicker np = (NumberPicker) view.findViewById(R.id.score_picker);
// Set initial value
np.setValue((int) getPresenter().mangaSync.score);
}
}
}
@@ -0,0 +1,186 @@
package eu.kanade.tachiyomi.ui.manga.myanimelist;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import javax.inject.Inject;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.database.models.MangaSync;
import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager;
import eu.kanade.tachiyomi.data.mangasync.services.MyAnimeList;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import eu.kanade.tachiyomi.util.EventBusHook;
import eu.kanade.tachiyomi.util.ToastUtil;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import timber.log.Timber;
public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> {
@Inject DatabaseHelper db;
@Inject MangaSyncManager syncManager;
protected MyAnimeList myAnimeList;
protected Manga manga;
protected MangaSync mangaSync;
private String query;
private static final int GET_MANGA_SYNC = 1;
private static final int GET_SEARCH_RESULTS = 2;
private static final int REFRESH = 3;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState != null) {
onProcessRestart();
}
myAnimeList = syncManager.getMyAnimeList();
restartableLatestCache(GET_MANGA_SYNC,
() -> db.getMangaSync(manga, myAnimeList).createObservable()
.doOnNext(mangaSync -> this.mangaSync = mangaSync)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()),
MyAnimeListFragment::setMangaSync);
restartableLatestCache(GET_SEARCH_RESULTS,
() -> myAnimeList.search(query)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()),
(view, results) -> {
view.setSearchResults(results);
}, (view, error) -> {
Timber.e(error.getMessage());
view.setSearchResultsError();
});
restartableFirst(REFRESH,
() -> myAnimeList.getList()
.flatMap(myList -> {
for (MangaSync myManga : myList) {
if (myManga.remote_id == mangaSync.remote_id) {
mangaSync.copyPersonalFrom(myManga);
mangaSync.total_chapters = myManga.total_chapters;
return Observable.just(mangaSync);
}
}
return Observable.error(new Exception("Could not find manga"));
})
.flatMap(myManga -> db.insertMangaSync(myManga).createObservable())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()),
(view, result) -> view.onRefreshDone(),
(view, error) -> view.onRefreshError());
}
private void onProcessRestart() {
stop(GET_MANGA_SYNC);
stop(GET_SEARCH_RESULTS);
stop(REFRESH);
}
@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_MANGA_SYNC);
}
private void updateRemote() {
add(myAnimeList.update(mangaSync)
.flatMap(response -> db.insertMangaSync(mangaSync).createObservable())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(next -> {},
error -> {
Timber.e(error.getMessage());
// Restart on error to set old values
start(GET_MANGA_SYNC);
}
));
}
public void searchManga(String query) {
if (TextUtils.isEmpty(query) || query.equals(this.query))
return;
this.query = query;
start(GET_SEARCH_RESULTS);
}
public void restartSearch() {
this.query = null;
stop(GET_SEARCH_RESULTS);
}
public void registerManga(MangaSync manga) {
manga.manga_id = this.manga.id;
add(myAnimeList.bind(manga)
.flatMap(response -> {
if (response.isSuccessful()) {
return db.insertMangaSync(manga).createObservable();
}
return Observable.error(new Exception("Could not bind manga"));
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(manga2 -> {},
error -> ToastUtil.showShort(getContext(), error.getMessage())));
}
public String[] getAllStatus(Context context) {
return new String[] {
context.getString(R.string.reading),
context.getString(R.string.completed),
context.getString(R.string.on_hold),
context.getString(R.string.dropped),
context.getString(R.string.plan_to_read)
};
}
public int getIndexFromStatus() {
return mangaSync.status == 6 ? 4 : mangaSync.status - 1;
}
public void setStatus(int index) {
mangaSync.status = index == 4 ? 6 : index + 1;
updateRemote();
}
public void setScore(int score) {
mangaSync.score = score;
updateRemote();
}
public void setLastChapterRead(int chapterNumber) {
mangaSync.last_chapter_read = chapterNumber;
updateRemote();
}
public void refresh() {
if (mangaSync != null) {
start(REFRESH);
}
}
}