From e548cbf171885cc385d4236e6b1bd5ea64c7a543 Mon Sep 17 00:00:00 2001 From: inorichi Date: Mon, 28 Dec 2015 01:13:52 +0100 Subject: [PATCH] Allow to create/remove categories. Some refactoring. --- app/build.gradle | 1 + .../data/database/DatabaseHelper.java | 6 + .../data/download/DownloadManager.java | 2 +- .../data/preference/PreferencesHelper.java | 9 +- .../injection/component/AppComponent.java | 5 +- .../ui/base/activity/BaseActivity.java | 19 ++- .../ui/decoration/DividerItemDecoration.java | 4 +- .../ui/library/LibraryCategoryFragment.java | 55 +++---- .../mangafeed/ui/library/LibraryFragment.java | 10 ++ .../ui/library/LibraryPresenter.java | 17 +- .../ui/library/category/CategoryAdapter.java | 60 +++++++ .../ui/library/category/CategoryFragment.java | 150 ++++++++++++++++++ .../ui/library/category/CategoryHolder.java | 45 ++++++ .../library/category/CategoryPresenter.java | 39 +++++ .../mangafeed/ui/main/MainActivity.java | 67 ++++++-- .../mangafeed/ui/manga/MangaActivity.java | 10 +- .../ui/manga/chapter/ChaptersFragment.java | 10 +- .../ui/setting/SettingsActivity.java | 6 +- .../res/drawable-hdpi/ic_action_add_18dp.png | Bin 0 -> 134 bytes .../res/drawable-ldpi/ic_action_add_18dp.png | Bin 0 -> 119 bytes .../res/drawable-mdpi/ic_action_add_18dp.png | Bin 0 -> 116 bytes .../res/drawable-xhdpi/ic_action_add_18dp.png | Bin 0 -> 168 bytes .../drawable-xxhdpi/ic_action_add_18dp.png | Bin 0 -> 242 bytes .../drawable-xxxhdpi/ic_action_add_18dp.png | Bin 0 -> 500 bytes .../res/layout/fragment_edit_categories.xml | 26 +++ .../main/res/layout/item_edit_categories.xml | 39 +++++ app/src/main/res/menu/category_selection.xml | 12 ++ app/src/main/res/menu/library.xml | 10 +- app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 6 +- build.gradle | 1 + 31 files changed, 539 insertions(+), 75 deletions(-) create mode 100644 app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryAdapter.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryFragment.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryHolder.java create mode 100644 app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryPresenter.java create mode 100644 app/src/main/res/drawable-hdpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_add_18dp.png create mode 100644 app/src/main/res/layout/fragment_edit_categories.xml create mode 100644 app/src/main/res/layout/item_edit_categories.xml create mode 100644 app/src/main/res/menu/category_selection.xml diff --git a/app/build.gradle b/app/build.gradle index 4bd222b693..3350298b47 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -113,6 +113,7 @@ dependencies { compile 'com.github.dmytrodanylyk.android-process-button:library:1.0.4' compile 'eu.davidea:flexible-adapter:4.2.0@aar' compile 'com.nononsenseapps:filepicker:2.5.0' + compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' compile "com.google.dagger:dagger:$DAGGER_VERSION" apt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" diff --git a/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java b/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java index 31deeda4fb..8beea887b2 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java @@ -367,6 +367,12 @@ public class DatabaseHelper { .prepare(); } + public PreparedDeleteCollectionOfObjects deleteCategories(List categories) { + return db.delete() + .objects(categories) + .prepare(); + } + public PreparedPutObject insertMangaCategory(MangaCategory mangaCategory) { return db.put() .object(mangaCategory) diff --git a/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java b/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java index 67e2254f90..95db355258 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/download/DownloadManager.java @@ -71,7 +71,7 @@ public class DownloadManager { if (threadsNumberSubscription != null && !threadsNumberSubscription.isUnsubscribed()) threadsNumberSubscription.unsubscribe(); - threadsNumberSubscription = preferences.getDownloadTheadsObservable() + threadsNumberSubscription = preferences.downloadThreads().asObservable() .subscribe(threadsNumber::onNext); downloadsSubscription = downloadsQueueSubject diff --git a/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java b/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java index b610d25882..2844947b5c 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java @@ -13,7 +13,6 @@ import java.io.File; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService; import eu.kanade.mangafeed.data.source.base.Source; -import rx.Observable; public class PreferencesHelper { @@ -138,12 +137,8 @@ public class PreferencesHelper { prefs.edit().putString(getKey(R.string.pref_download_directory_key), path).apply(); } - public int getDownloadThreads() { - return prefs.getInt(getKey(R.string.pref_download_slots_key), 1); - } - - public Observable getDownloadTheadsObservable() { - return rxPrefs.getInteger(getKey(R.string.pref_download_slots_key), 1).asObservable(); + public Preference downloadThreads() { + return rxPrefs.getInteger(getKey(R.string.pref_download_slots_key), 1); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java index 5a6df1e9ac..7f1f153334 100644 --- a/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java +++ b/app/src/main/java/eu/kanade/mangafeed/injection/component/AppComponent.java @@ -14,7 +14,7 @@ import eu.kanade.mangafeed.injection.module.AppModule; 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.LibraryCategoryFragment; +import eu.kanade.mangafeed.ui.library.category.CategoryPresenter; import eu.kanade.mangafeed.ui.library.LibraryPresenter; import eu.kanade.mangafeed.ui.manga.MangaActivity; import eu.kanade.mangafeed.ui.manga.MangaPresenter; @@ -43,14 +43,13 @@ public interface AppComponent { void inject(ReaderPresenter readerPresenter); void inject(DownloadPresenter downloadPresenter); void inject(MyAnimeListPresenter myAnimeListPresenter); + void inject(CategoryPresenter categoryPresenter); void inject(ReaderActivity readerActivity); void inject(MangaActivity mangaActivity); void inject(SettingsAccountsFragment settingsAccountsFragment); void inject(SettingsActivity settingsActivity); - void inject(LibraryCategoryFragment libraryCategoryFragment); - void inject(Source source); void inject(MyAnimeList myAnimeList); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseActivity.java index b67399a929..a887156af8 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/base/activity/BaseActivity.java @@ -1,14 +1,27 @@ package eu.kanade.mangafeed.ui.base.activity; -import android.content.Context; +import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import de.greenrobot.event.EventBus; +import icepick.Icepick; public class BaseActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + Icepick.restoreInstanceState(this, savedState); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Icepick.saveInstanceState(this, outState); + } + protected void setupToolbar(Toolbar toolbar) { setSupportActionBar(toolbar); if (getSupportActionBar() != null) @@ -35,10 +48,6 @@ public class BaseActivity extends AppCompatActivity { getSupportActionBar().setSubtitle(getString(titleResource)); } - public Context getActivity() { - return this; - } - @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/decoration/DividerItemDecoration.java b/app/src/main/java/eu/kanade/mangafeed/ui/decoration/DividerItemDecoration.java index 1a449234f6..86cb799d63 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/decoration/DividerItemDecoration.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/decoration/DividerItemDecoration.java @@ -33,8 +33,8 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration { } @Override - public void onDrawOver(Canvas c, RecyclerView parent) { - if (mDivider == null) { super.onDrawOver(c, parent); return; } + public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { + if (mDivider == null) { super.onDrawOver(c, parent, state); return; } if (getOrientation(parent) == LinearLayoutManager.VERTICAL) { final int left = parent.getPaddingLeft(); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java index 2ca2e30f73..8fd3f7b94e 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryCategoryFragment.java @@ -14,15 +14,11 @@ import com.f2prateek.rx.preferences.Preference; import java.util.List; -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.database.models.Category; import eu.kanade.mangafeed.data.database.models.Manga; -import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.event.LibraryMangasEvent; import eu.kanade.mangafeed.ui.base.activity.BaseActivity; import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder; @@ -37,8 +33,6 @@ import rx.Subscription; public class LibraryCategoryFragment extends BaseFragment implements ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener { - @Inject PreferencesHelper preferences; - @Bind(R.id.library_mangas) AutofitRecyclerView recycler; @State Category category; @@ -47,20 +41,12 @@ public class LibraryCategoryFragment extends BaseFragment implements private Subscription numColumnsSubscription; - private static final int INVALID_POSITION = -1; - public static LibraryCategoryFragment newInstance(Category category) { LibraryCategoryFragment fragment = new LibraryCategoryFragment(); fragment.category = category; return fragment; } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - App.get(getActivity()).getComponent().inject(this); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { // Inflate the layout for this fragment @@ -75,8 +61,8 @@ public class LibraryCategoryFragment extends BaseFragment implements Preference columnsPref = getResources().getConfiguration() .orientation == Configuration.ORIENTATION_PORTRAIT ? - preferences.portraitColumns() : - preferences.landscapeColumns(); + getLibraryPresenter().preferences.portraitColumns() : + getLibraryPresenter().preferences.landscapeColumns(); numColumnsSubscription = columnsPref.asObservable() .subscribe(recycler::setSpanCount); @@ -110,6 +96,7 @@ public class LibraryCategoryFragment extends BaseFragment implements @EventBusHook public void onEventMainThread(LibraryMangasEvent event) { + destroyActionModeIfNeeded(); setMangas(event.getMangas().get(category.id)); } @@ -128,7 +115,7 @@ public class LibraryCategoryFragment extends BaseFragment implements @Override public boolean onListItemClick(int position) { - if (actionMode != null && position != INVALID_POSITION) { + if (actionMode != null && position != -1) { toggleSelection(position); return true; } else { @@ -145,6 +132,22 @@ public class LibraryCategoryFragment extends BaseFragment implements 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)); + } + @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.library_selection, menu); @@ -169,19 +172,17 @@ public class LibraryCategoryFragment extends BaseFragment implements actionMode = null; } - private void toggleSelection(int position) { - adapter.toggleSelection(position, false); - - int count = adapter.getSelectedItemCount(); - if (count == 0) { + public void destroyActionModeIfNeeded() { + if (actionMode != null) { actionMode.finish(); - } else { - setContextTitle(count); - actionMode.invalidate(); } } - private void setContextTitle(int count) { - actionMode.setTitle(getString(R.string.selected_chapters_title, count)); + private LibraryFragment getLibraryFragment() { + return (LibraryFragment) getParentFragment(); + } + + private LibraryPresenter getLibraryPresenter() { + return getLibraryFragment().getPresenter(); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java index 198a0be637..b7b27664f3 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.Menu; @@ -21,6 +22,7 @@ import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.database.models.Category; import eu.kanade.mangafeed.data.sync.LibraryUpdateService; import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment; +import eu.kanade.mangafeed.ui.library.category.CategoryFragment; import eu.kanade.mangafeed.ui.main.MainActivity; import nucleus.factory.RequiresPresenter; @@ -82,12 +84,20 @@ public class LibraryFragment extends BaseRxFragment { getActivity().startService(intent); } + return true; + case R.id.action_edit_categories: + onEditCategories(); return true; } return super.onOptionsItemSelected(item); } + private void onEditCategories() { + Fragment fragment = CategoryFragment.newInstance(); + ((MainActivity) getActivity()).pushFragment(fragment); + } + public void onNextCategories(List categories) { List actualCategories = new ArrayList<>(); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java index 8fef13b561..da132d0f99 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java @@ -11,21 +11,25 @@ import javax.inject.Inject; import de.greenrobot.event.EventBus; import eu.kanade.mangafeed.data.cache.CoverCache; import eu.kanade.mangafeed.data.database.DatabaseHelper; +import eu.kanade.mangafeed.data.database.models.Category; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.preference.PreferencesHelper; import eu.kanade.mangafeed.data.source.SourceManager; import eu.kanade.mangafeed.event.LibraryMangasEvent; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import rx.Observable; +import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; public class LibraryPresenter extends BasePresenter { @Inject DatabaseHelper db; - @Inject PreferencesHelper prefs; + @Inject PreferencesHelper preferences; @Inject CoverCache coverCache; @Inject SourceManager sourceManager; + protected List categories; + private static final int GET_CATEGORIES = 1; @Override @@ -33,7 +37,7 @@ public class LibraryPresenter extends BasePresenter { super.onCreate(savedState); restartableLatestCache(GET_CATEGORIES, - () -> db.getCategories().createObservable(), + this::getCategoriesObservable, LibraryFragment::onNextCategories); start(GET_CATEGORIES); @@ -41,9 +45,16 @@ public class LibraryPresenter extends BasePresenter { add(getLibraryMangasObservable() .subscribe(mangas -> EventBus.getDefault().postSticky(new LibraryMangasEvent(mangas)))); + } - public Observable>> getLibraryMangasObservable() { + public Observable> getCategoriesObservable() { + return db.getCategories().createObservable() + .doOnNext(categories -> this.categories = categories) + .observeOn(AndroidSchedulers.mainThread()); + } + + private Observable>> getLibraryMangasObservable() { return db.getLibraryMangas().createObservable() .flatMap(mangas -> Observable.from(mangas) .groupBy(manga -> manga.category) diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryAdapter.java new file mode 100644 index 0000000000..50810a650f --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryAdapter.java @@ -0,0 +1,60 @@ +package eu.kanade.mangafeed.ui.library.category; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.amulyakhare.textdrawable.util.ColorGenerator; + +import java.util.List; + +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.kanade.mangafeed.R; +import eu.kanade.mangafeed.data.database.models.Category; + +public class CategoryAdapter extends FlexibleAdapter { + + private CategoryFragment fragment; + private ColorGenerator generator; + + public CategoryAdapter(CategoryFragment fragment) { + this.fragment = fragment; + setHasStableIds(true); + generator = ColorGenerator.DEFAULT; + } + + public void setItems(List items) { + mItems = items; + notifyDataSetChanged(); + } + + @Override + public long getItemId(int position) { + return mItems.get(position).id; + } + + @Override + public void updateDataSet(String param) { + + } + + @Override + public CategoryHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(fragment.getActivity()); + View v = inflater.inflate(R.layout.item_edit_categories, parent, false); + return new CategoryHolder(v, this, fragment); + } + + @Override + public void onBindViewHolder(CategoryHolder holder, int position) { + final Category category = getItem(position); + holder.onSetValues(category, generator); + + //When user scrolls this bind the correct selection status + holder.itemView.setActivated(isSelected(position)); + } + + public ColorGenerator getColorGenerator() { + return generator; + } +} diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryFragment.java new file mode 100644 index 0000000000..dc34b29d43 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryFragment.java @@ -0,0 +1,150 @@ +package eu.kanade.mangafeed.ui.library.category; + +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.content.res.ResourcesCompat; +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 com.afollestad.materialdialogs.MaterialDialog; + +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import eu.kanade.mangafeed.R; +import eu.kanade.mangafeed.data.database.models.Category; +import eu.kanade.mangafeed.ui.base.activity.BaseActivity; +import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder; +import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment; +import eu.kanade.mangafeed.ui.decoration.DividerItemDecoration; +import eu.kanade.mangafeed.ui.library.LibraryCategoryAdapter; +import nucleus.factory.RequiresPresenter; +import rx.Observable; + +@RequiresPresenter(CategoryPresenter.class) +public class CategoryFragment extends BaseRxFragment + implements ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener { + + @Bind(R.id.categories_list) RecyclerView recycler; + @Bind(R.id.fab) FloatingActionButton fab; + + private CategoryAdapter adapter; + private ActionMode actionMode; + + public static CategoryFragment newInstance() { + return new CategoryFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { + View view = inflater.inflate(R.layout.fragment_edit_categories, container, false); + ButterKnife.bind(this, view); + + setToolbarTitle(R.string.action_edit_categories); + + adapter = new CategoryAdapter(this); + recycler.setLayoutManager(new LinearLayoutManager(getActivity())); + recycler.setHasFixedSize(true); + recycler.setAdapter(adapter); + recycler.addItemDecoration(new DividerItemDecoration( + ResourcesCompat.getDrawable(getResources(), R.drawable.line_divider, null))); + + fab.setOnClickListener(v -> { + new MaterialDialog.Builder(getActivity()) + .title(R.string.action_add_category) + .input(R.string.name, 0, false, (dialog, input) -> { + getPresenter().createCategory(input.toString()); + }).show(); + }); + + return view; + } + + public void setCategories(List categories) { + destroyActionModeIfNeeded(); + adapter.setItems(categories); + } + + private List getSelectedCategories() { + // Create a blocking copy of the selected categories + return Observable.from(adapter.getSelectedItems()) + .map(adapter::getItem).toList().toBlocking().single(); + } + + @Override + public boolean onListItemClick(int position) { + if (actionMode != null && position != -1) { + toggleSelection(position); + return true; + } else { + return false; + } + } + + @Override + public void onListItemLongClick(int position) { + if (actionMode == null) + actionMode = ((BaseActivity) getActivity()).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)); + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + mode.getMenuInflater().inflate(R.menu.category_selection, menu); + adapter.setMode(LibraryCategoryAdapter.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_delete: + getPresenter().deleteCategories(getSelectedCategories()); + return true; + } + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + adapter.setMode(LibraryCategoryAdapter.MODE_SINGLE); + adapter.clearSelection(); + actionMode = null; + } + + public void destroyActionModeIfNeeded() { + if (actionMode != null) { + actionMode.finish(); + } + } + +} diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryHolder.java new file mode 100644 index 0000000000..9fdb179d7a --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryHolder.java @@ -0,0 +1,45 @@ +package eu.kanade.mangafeed.ui.library.category; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; +import eu.kanade.mangafeed.R; +import eu.kanade.mangafeed.data.database.models.Category; +import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder; + +public class CategoryHolder extends FlexibleViewHolder { + + private View view; + + @Bind(R.id.image) ImageView image; + @Bind(R.id.title) TextView title; + + public CategoryHolder(View view, CategoryAdapter adapter, OnListItemClickListener listener) { + super(view, adapter, listener); + ButterKnife.bind(this, view); + this.view = view; + } + + public void onSetValues(Category category, ColorGenerator generator) { + title.setText(category.name); + image.setImageDrawable(getRound(category.name.substring(0, 1), generator)); + } + + private TextDrawable getRound(String text, ColorGenerator generator) { + return TextDrawable.builder().buildRound(text, generator.getColor(text)); + } + + @OnClick(R.id.image) + void onImageClick() { + // Simulate long click on this view to enter selection mode + onLongClick(view); + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryPresenter.java new file mode 100644 index 0000000000..42a9712459 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/category/CategoryPresenter.java @@ -0,0 +1,39 @@ +package eu.kanade.mangafeed.ui.library.category; + +import android.os.Bundle; + +import java.util.List; + +import javax.inject.Inject; + +import eu.kanade.mangafeed.data.database.DatabaseHelper; +import eu.kanade.mangafeed.data.database.models.Category; +import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; +import rx.android.schedulers.AndroidSchedulers; + +public class CategoryPresenter extends BasePresenter { + + @Inject DatabaseHelper db; + + private static final int GET_CATEGORIES = 1; + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + + restartableLatestCache(GET_CATEGORIES, + () -> db.getCategories().createObservable() + .observeOn(AndroidSchedulers.mainThread()), + CategoryFragment::setCategories); + + start(GET_CATEGORIES); + } + + public void createCategory(String name) { + db.insertCategory(Category.create(name)).createObservable().subscribe(); + } + + public void deleteCategories(List categories) { + db.deleteCategories(categories).createObservable().subscribe(); + } +} diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/main/MainActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/main/MainActivity.java index 7fe2252711..3e47ba6ffe 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/main/MainActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/main/MainActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.design.widget.AppBarLayout; import android.support.v4.app.Fragment; +import android.support.v4.widget.DrawerLayout; import android.support.v7.widget.Toolbar; import android.widget.FrameLayout; @@ -19,23 +20,23 @@ import eu.kanade.mangafeed.ui.catalogue.CatalogueFragment; import eu.kanade.mangafeed.ui.download.DownloadFragment; import eu.kanade.mangafeed.ui.library.LibraryFragment; import eu.kanade.mangafeed.ui.setting.SettingsActivity; +import icepick.State; import nucleus.view.ViewWithPresenter; public class MainActivity extends BaseActivity { @Bind(R.id.appbar) AppBarLayout appBar; @Bind(R.id.toolbar) Toolbar toolbar; - @Bind(R.id.drawer_container) FrameLayout container; private Drawer drawer; private FragmentStack fragmentStack; - private final static String SELECTED_ITEM = "selected_item"; + @State int selectedItem; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); setContentView(R.layout.activity_main); ButterKnife.bind(this); @@ -52,6 +53,13 @@ public class MainActivity extends BaseActivity { .withRootView(container) .withToolbar(toolbar) .withActionBarDrawerToggleAnimated(true) + .withOnDrawerNavigationListener(view -> { + if (fragmentStack.size() > 1) { + onBackPressed(); + return true; + } + return false; + }) .addDrawerItems( new PrimaryDrawerItem() .withName(R.string.label_library) @@ -70,7 +78,7 @@ public class MainActivity extends BaseActivity { .withIdentifier(R.id.nav_drawer_settings) .withSelectable(false) ) - .withSavedInstance(savedInstanceState) + .withSavedInstance(savedState) .withOnDrawerItemClickListener( (view, position, drawerItem) -> { if (drawerItem != null) { @@ -97,15 +105,23 @@ public class MainActivity extends BaseActivity { ) .build(); - if (savedInstanceState == null) + if (savedState != null) { + // Recover icon state after rotation + if (fragmentStack.size() > 1) { + showBackArrow(); + } + + // Set saved selection + drawer.setSelection(selectedItem, false); + } else { + // Set default selection drawer.setSelection(R.id.nav_drawer_library); - else - drawer.setSelection(savedInstanceState.getInt(SELECTED_ITEM), false); + } } @Override protected void onSaveInstanceState(Bundle outState) { - outState.putInt(SELECTED_ITEM, drawer.getCurrentSelection()); + selectedItem = drawer.getCurrentSelection(); super.onSaveInstanceState(outState); } @@ -113,8 +129,37 @@ public class MainActivity extends BaseActivity { fragmentStack.replace(fragment); } - public Fragment getActiveFragment() { - return fragmentStack.peek(); + public void pushFragment(Fragment fragment) { + fragmentStack.push(fragment); + if (fragmentStack.size() > 1) { + showBackArrow(); + } + } + + @Override + public void onBackPressed() { + if (!fragmentStack.pop()) { + super.onBackPressed(); + } else if (fragmentStack.size() == 1) { + showHamburgerIcon(); + drawer.getActionBarDrawerToggle().syncState(); + } + } + + private void showHamburgerIcon() { + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(false); + drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(true); + drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); + } + } + + private void showBackArrow() { + if (getSupportActionBar() != null) { + drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); + } } public Toolbar getToolbar() { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java index e37007b29b..bf3dbdafd7 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/MangaActivity.java @@ -49,8 +49,8 @@ public class MangaActivity extends BaseRxActivity { } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); App.get(this).getComponent().inject(this); setContentView(R.layout.activity_manga); ButterKnife.bind(this); @@ -64,14 +64,12 @@ public class MangaActivity extends BaseRxActivity { setupViewPager(); - if (savedInstanceState == null) + if (savedState == null) getPresenter().queryManga(manga_id); } private void setupViewPager() { - adapter = new MangaDetailAdapter( - getSupportFragmentManager(), - getActivity()); + adapter = new MangaDetailAdapter(getSupportFragmentManager(), this); view_pager.setAdapter(adapter); tabs.setupWithViewPager(view_pager); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java index 5af5dd895e..4c09e7cf01 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/chapter/ChaptersFragment.java @@ -145,7 +145,7 @@ public class ChaptersFragment extends BaseRxFragment implemen if (getPresenter().getChapters().isEmpty()) initialFetchChapters(); - closeActionMode(); + destroyActionModeIfNeeded(); adapter.setItems(chapters); } @@ -254,7 +254,7 @@ public class ChaptersFragment extends BaseRxFragment implemen return Observable.from(chapters); } - public void closeActionMode() { + public void destroyActionModeIfNeeded() { if (actionMode != null) { actionMode.finish(); } @@ -283,7 +283,7 @@ public class ChaptersFragment extends BaseRxFragment implemen .doOnCompleted(adapter::notifyDataSetChanged); getPresenter().downloadChapters(observable); - closeActionMode(); + destroyActionModeIfNeeded(); return true; } @@ -311,7 +311,7 @@ public class ChaptersFragment extends BaseRxFragment implemen .finallyDo(dialog::dismiss); getPresenter().deleteChapters(observable); - closeActionMode(); + destroyActionModeIfNeeded(); return true; } @@ -347,7 +347,7 @@ public class ChaptersFragment extends BaseRxFragment implemen } private void setContextTitle(int count) { - actionMode.setTitle(getString(R.string.selected_chapters_title, count)); + actionMode.setTitle(getString(R.string.label_selected, count)); } public void setSortIcon() { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsActivity.java b/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsActivity.java index 9ff14e9d8d..28a5577486 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsActivity.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsActivity.java @@ -22,15 +22,15 @@ public class SettingsActivity extends BaseActivity { @Bind(R.id.toolbar) Toolbar toolbar; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); App.get(this).getComponent().inject(this); setContentView(R.layout.activity_preferences); ButterKnife.bind(this); setupToolbar(toolbar); - if (savedInstanceState == null) + if (savedState == null) getFragmentManager().beginTransaction().replace(R.id.settings_content, new SettingsMainFragment()) .commit(); diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_18dp.png b/app/src/main/res/drawable-hdpi/ic_action_add_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7800ba33d627ceed4ab719da9cd8ce23ec437f50 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCUr!gukcwMxZ*1gbFc4sJ_#S_2 zi=+a}Kg)xR>oyqX8t-HTDguHCt{uz}7K4H82V(|pMmHWP|G^zrFstG^^W;Nyen|ElzrUa8o?i*N5^xwE?&r!@^WUx-YfBWA` Sr8z*87(8A5T-G@yGywqEH70fd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_18dp.png b/app/src/main/res/drawable-mdpi/ic_action_add_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ed40b2b21627006beb1e6fa808e20b2304b557eb GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzYfl%)kcwMxuWjUHP!M1~@MeF> znmG=xQ@EGZuJibqIeRuQ1H*wwjgkxu4fTw>Kj|F+>HX8fz;N7};aHVL;lI$d7eEmP MPgg&ebxsLQ09S`3zyJUM literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_18dp.png b/app/src/main/res/drawable-xhdpi/ic_action_add_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..185be8a769b4b5dccc8ca553f2f698fa5a801099 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=`JOJ0Ar-gY-rC5?V8Fxd_;&x6 zOYK(zopr04XFQCIA2c literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_18dp.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab780a89de78daeb3faaf82d295a0007449cbe9 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoJ3U<-Ln>~)y>^h7!GMF=@LRmq z+y&>mxMW_69gx@ZT&eHQz~I2Zz`?-4$e_T$z{1eLz#zcDzyuQfb1j#FI8ecEPzqOh nF96QO&p@}7L530LjD$$`Hy8gfbhUB40GZ+G>gTe~DWM4f^m`)q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_add_18dp.png b/app/src/main/res/drawable-xxxhdpi/ic_action_add_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e6ca376b305d4bb78c96ec2aa1a40d4a1e0b30fb GIT binary patch literal 500 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrVBGEL;uunK>+K!KtV0eW4T-IC ziobUSd{mfstJ&ksqIb4U7cSV$n3`ZD((~z4t%0<4>w`Z>)r>YrF#?T%gPJYNGLzP* zx0!3bel-95^YypiZj(G#C$YO-aD8r4A4d_}hCbGJzyF!^yf)aC7<1~ysqE!5gp2nk zTQc96-ukcBXq}-uLnZT#sr$c0ym9{+C0@)j!MfqJ2ZJ~xhXVtXKm&sS1Cs*-2Lq!5 z0}D=$ok2scD?>Eno;<;i_Uy==^4RoSYhQ}~{v2<)E%jsn z;UAKm3Uy^YJD-+6+jH#Bb77x1=jSJHNo{=pxA?o!^0_~6eVXqdu+zT2&+zHo>(jp1 zG + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_edit_categories.xml b/app/src/main/res/layout/item_edit_categories.xml new file mode 100644 index 0000000000..2df67dfd02 --- /dev/null +++ b/app/src/main/res/layout/item_edit_categories.xml @@ -0,0 +1,39 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/category_selection.xml b/app/src/main/res/menu/category_selection.xml new file mode 100644 index 0000000000..d31a6945e2 --- /dev/null +++ b/app/src/main/res/menu/category_selection.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/library.xml b/app/src/main/res/menu/library.xml index dad70a02df..b1428ce391 100644 --- a/app/src/main/res/menu/library.xml +++ b/app/src/main/res/menu/library.xml @@ -1,17 +1,25 @@ + + app:actionViewClass="android.support.v7.widget.SearchView" /> + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 5fd4e58157..9445bffbe0 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,6 +2,11 @@ 16dp 16dp + 16dp + 16dp + 16dp + 16dp + 16dp 24sp 22sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f93c3b3a7e..c93109e772 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,12 +1,15 @@ Mangafeed + Name + Settings Download queue My library Recent updates Catalogues + Selected: %1$d Settings @@ -19,6 +22,8 @@ Delete Update Edit + Add category + Edit categories Sort up Sort down Unread @@ -118,7 +123,6 @@ Chapters - Selected: %1$d No title Downloaded Queued diff --git a/build.gradle b/build.gradle index 5a595d4a21..4a7361f908 100644 --- a/build.gradle +++ b/build.gradle @@ -22,5 +22,6 @@ allprojects { maven { url "https://clojars.org/repo/" } maven { url "http://dl.bintray.com/davideas/maven" } maven { url "https://jitpack.io" } + maven { url 'http://dl.bintray.com/amulyakhare/maven' } } }