Category improvements

This commit is contained in:
inorichi 2015-12-30 14:10:31 +01:00
parent e6b7a79bee
commit 384bc3c690
16 changed files with 153 additions and 62 deletions

View file

@ -38,6 +38,11 @@
android:label="@string/label_settings"
android:parentActivityName=".ui.main.MainActivity" >
</activity>
<activity
android:name=".ui.library.category.CategoryActivity"
android:label="@string/label_categories"
android:parentActivityName=".ui.main.MainActivity">
</activity>
<activity
android:name=".ui.setting.SettingsDownloadsFragment$CustomLayoutPickerActivity"

View file

@ -0,0 +1,51 @@
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.kanade.mangafeed.ui.base.fab;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
}
@Override
public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
final View directTargetChild, final View target, final int nestedScrollAxes) {
// Ensure we react to vertical scrolling
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
|| super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
final View target, final int dxConsumed, final int dyConsumed,
final int dxUnconsumed, final int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
// User scrolled down and the FAB is currently visible -> hide the FAB
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
// User scrolled up and the FAB is currently not visible -> show the FAB
child.show();
}
}
}

View file

@ -1,12 +1,26 @@
package eu.kanade.mangafeed.ui.base.fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.ui.base.activity.BaseActivity;
import icepick.Icepick;
public class BaseFragment extends Fragment {
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
Icepick.restoreInstanceState(this, savedState);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
public void setToolbarTitle(String title) {
getBaseActivity().setToolbarTitle(title);
}

View file

@ -33,7 +33,6 @@ import eu.kanade.mangafeed.ui.main.MainActivity;
import eu.kanade.mangafeed.ui.manga.MangaActivity;
import eu.kanade.mangafeed.util.ToastUtil;
import eu.kanade.mangafeed.widget.EndlessScrollListener;
import icepick.Icepick;
import icepick.State;
import nucleus.factory.RequiresPresenter;
import rx.Subscription;
@ -66,7 +65,6 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> {
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
Icepick.restoreInstanceState(this, savedState);
setHasOptionsMenu(true);
}
@ -168,12 +166,6 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter> {
super.onDestroyView();
}
@Override
public void onSaveInstanceState(Bundle outState) {
Icepick.saveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
private void initializeSearchSubscription() {
queryDebouncerSubject = PublishSubject.create();
queryDebouncerSubscription = queryDebouncerSubject

View file

@ -24,7 +24,6 @@ import eu.kanade.mangafeed.ui.base.fragment.BaseFragment;
import eu.kanade.mangafeed.ui.manga.MangaActivity;
import eu.kanade.mangafeed.util.EventBusHook;
import eu.kanade.mangafeed.widget.AutofitRecyclerView;
import icepick.Icepick;
import icepick.State;
import rx.Subscription;
@ -49,7 +48,6 @@ public class LibraryCategoryFragment extends BaseFragment
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_library_category, container, false);
ButterKnife.bind(this, view);
Icepick.restoreInstanceState(this, savedState);
adapter = new LibraryCategoryAdapter(this);
recycler.setHasFixedSize(true);
@ -98,7 +96,6 @@ public class LibraryCategoryFragment extends BaseFragment
@Override
public void onSaveInstanceState(Bundle outState) {
Icepick.saveInstanceState(this, outState);
adapter.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}

View file

@ -5,7 +5,6 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
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.support.v7.view.ActionMode;
import android.util.Pair;
@ -31,24 +30,26 @@ import eu.kanade.mangafeed.data.database.models.Category;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.sync.LibraryUpdateService;
import eu.kanade.mangafeed.event.LibraryMangasEvent;
import eu.kanade.mangafeed.ui.base.activity.BaseActivity;
import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment;
import eu.kanade.mangafeed.ui.library.category.CategoryFragment;
import eu.kanade.mangafeed.ui.library.category.CategoryActivity;
import eu.kanade.mangafeed.ui.main.MainActivity;
import icepick.State;
import nucleus.factory.RequiresPresenter;
@RequiresPresenter(LibraryPresenter.class)
public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
implements ActionMode.Callback {
TabLayout tabs;
AppBarLayout appBar;
@Bind(R.id.view_pager) ViewPager viewPager;
private TabLayout tabs;
private AppBarLayout appBar;
protected LibraryAdapter adapter;
private ActionMode actionMode;
@State int activeCategory;
public static LibraryFragment newInstance() {
return new LibraryFragment();
}
@ -68,12 +69,12 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
ButterKnife.bind(this, view);
appBar = ((MainActivity) getActivity()).getAppBar();
tabs = (TabLayout) inflater.inflate(R.layout.tab_layout, appBar, false);
tabs = (TabLayout) inflater.inflate(R.layout.library_tab_layout, appBar, false);
appBar.addView(tabs);
adapter = new LibraryAdapter(getChildFragmentManager());
viewPager.setAdapter(adapter);
tabs.setupWithViewPager(viewPager);
return view;
}
@ -81,9 +82,16 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
@Override
public void onDestroyView() {
appBar.removeView(tabs);
EventBus.getDefault().removeStickyEvent(LibraryMangasEvent.class);
super.onDestroyView();
}
@Override
public void onSaveInstanceState(Bundle bundle) {
activeCategory = viewPager.getCurrentItem();
super.onSaveInstanceState(bundle);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.library, menu);
@ -107,8 +115,8 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
}
private void onEditCategories() {
Fragment fragment = CategoryFragment.newInstance();
((MainActivity) getActivity()).pushFragment(fragment);
Intent intent = CategoryActivity.newIntent(getActivity());
startActivity(intent);
}
public void onNextLibraryUpdate(Pair<List<Category>, Map<Integer, List<Manga>>> pair) {
@ -125,6 +133,10 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
else if (!mangasInDefaultCategory && (!initialized || adapter.hasDefaultCategory())) {
setCategories(pair.first);
}
// Restore active category
if (!initialized) {
viewPager.setCurrentItem(activeCategory, false);
}
// Send the mangas to child fragments after the adapter is updated
EventBus.getDefault().postSticky(new LibraryMangasEvent(pair.second));
}
@ -139,8 +151,8 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
private void setCategories(List<Category> categories) {
adapter.setCategories(categories);
tabs.setupWithViewPager(viewPager);
tabs.setVisibility(categories.size() == 1 ? View.GONE : View.VISIBLE);
tabs.setTabsFromPagerAdapter(adapter);
tabs.setVisibility(categories.size() <= 1 ? View.GONE : View.VISIBLE);
}
public void setContextTitle(int count) {
@ -211,7 +223,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
public void createActionModeIfNeeded() {
if (actionMode == null) {
actionMode = ((BaseActivity) getActivity()).startSupportActionMode(this);
actionMode = getBaseActivity().startSupportActionMode(this);
}
}

View file

@ -59,7 +59,7 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
.observeOn(AndroidSchedulers.mainThread());
}
public Observable<List<Category>> getCategoriesObservable() {
private Observable<List<Category>> getCategoriesObservable() {
return db.getCategories().createObservable()
.doOnNext(categories -> this.categories = categories);
}

View file

@ -1,17 +1,17 @@
package eu.kanade.mangafeed.ui.library.category;
import android.content.Context;
import android.content.Intent;
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.support.v7.widget.Toolbar;
import android.support.v7.widget.helper.ItemTouchHelper;
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;
@ -21,19 +21,19 @@ 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.activity.BaseRxActivity;
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
import eu.kanade.mangafeed.ui.base.adapter.OnStartDragListener;
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<CategoryPresenter> implements
public class CategoryActivity extends BaseRxActivity<CategoryPresenter> implements
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener, OnStartDragListener {
@Bind(R.id.toolbar) Toolbar toolbar;
@Bind(R.id.categories_list) RecyclerView recycler;
@Bind(R.id.fab) FloatingActionButton fab;
@ -41,19 +41,20 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter> implemen
private ActionMode actionMode;
private ItemTouchHelper touchHelper;
public static CategoryFragment newInstance() {
return new CategoryFragment();
public static Intent newIntent(Context context) {
return new Intent(context, CategoryActivity.class);
}
@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);
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.activity_edit_categories);
ButterKnife.bind(this);
setToolbarTitle(R.string.action_edit_categories);
setupToolbar(toolbar);
adapter = new CategoryAdapter(this);
recycler.setLayoutManager(new LinearLayoutManager(getActivity()));
recycler.setLayoutManager(new LinearLayoutManager(this));
recycler.setHasFixedSize(true);
recycler.setAdapter(adapter);
recycler.addItemDecoration(new DividerItemDecoration(
@ -64,15 +65,13 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter> implemen
touchHelper.attachToRecyclerView(recycler);
fab.setOnClickListener(v -> {
new MaterialDialog.Builder(getActivity())
new MaterialDialog.Builder(this)
.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<Category> categories) {
@ -99,7 +98,7 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter> implemen
@Override
public void onListItemLongClick(int position) {
if (actionMode == null)
actionMode = ((BaseActivity) getActivity()).startSupportActionMode(this);
actionMode = startSupportActionMode(this);
toggleSelection(position);
}
@ -165,7 +164,7 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter> implemen
}
private void editCategory(Category category) {
new MaterialDialog.Builder(getActivity())
new MaterialDialog.Builder(this)
.title(R.string.action_rename_category)
.input(getString(R.string.name), category.name, false, (dialog, input) -> {
getPresenter().renameCategory(category, input.toString());

View file

@ -18,11 +18,11 @@ import eu.kanade.mangafeed.ui.base.adapter.ItemTouchHelperAdapter;
public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> implements
ItemTouchHelperAdapter {
private final CategoryFragment fragment;
private final CategoryActivity activity;
private final ColorGenerator generator;
public CategoryAdapter(CategoryFragment fragment) {
this.fragment = fragment;
public CategoryAdapter(CategoryActivity activity) {
this.activity = activity;
generator = ColorGenerator.DEFAULT;
setHasStableIds(true);
}
@ -44,9 +44,9 @@ public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> i
@Override
public CategoryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(fragment.getActivity());
LayoutInflater inflater = activity.getLayoutInflater();
View v = inflater.inflate(R.layout.item_edit_categories, parent, false);
return new CategoryHolder(v, this, fragment, fragment);
return new CategoryHolder(v, this, activity, activity);
}
@Override
@ -70,7 +70,7 @@ public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> i
}
}
fragment.getPresenter().reorderCategories(mItems);
activity.getPresenter().reorderCategories(mItems);
}
@Override

View file

@ -11,7 +11,7 @@ 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<CategoryFragment> {
public class CategoryPresenter extends BasePresenter<CategoryActivity> {
@Inject DatabaseHelper db;
@ -27,7 +27,7 @@ public class CategoryPresenter extends BasePresenter<CategoryFragment> {
() -> db.getCategories().createObservable()
.doOnNext(categories -> this.categories = categories)
.observeOn(AndroidSchedulers.mainThread()),
CategoryFragment::setCategories);
CategoryActivity::setCategories);
start(GET_CATEGORIES);
}

View file

@ -27,7 +27,6 @@ import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.download.DownloadService;
import eu.kanade.mangafeed.data.download.model.Download;
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;
@ -329,7 +328,7 @@ public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implemen
@Override
public void onListItemLongClick(int position) {
if (actionMode == null)
actionMode = ((BaseActivity) getActivity()).startSupportActionMode(this);
actionMode = getBaseActivity().startSupportActionMode(this);
toggleSelection(position);
}

View file

@ -2,13 +2,16 @@
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:gravity="center">
<include layout="@layout/toolbar"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:id="@+id/categories_list"
android:choiceMode="multipleChoice"
android:listSelector="@color/list_choice_pressed_bg_light" />
@ -17,10 +20,11 @@
android:id="@+id/fab"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="end|bottom"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
android:src="@drawable/ic_action_add_18dp"
app:borderWidth="0dp"/>
app:layout_anchor="@id/categories_list"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="eu.kanade.mangafeed.ui.base.fab.ScrollAwareFABBehavior"/>
</android.support.design.widget.CoordinatorLayout>

View file

@ -1,4 +1,6 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
@ -18,7 +20,7 @@
android:id="@+id/drawer_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/appbar">
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- the layout which will be the content of the activity (which will be hosted inside the drawer (NOT the list of the drawer)) -->
<FrameLayout
@ -28,4 +30,4 @@
</FrameLayout>
</FrameLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppTheme.Dark"
android:background="@color/colorPrimary"
android:elevation="4dp"
app:tabGravity="center"
app:tabMode="scrollable"
app:tabMinWidth="75dp"
app:tabIndicatorColor="@color/white"/>

View file

@ -7,4 +7,5 @@
android:background="@color/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppTheme.Dark"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.Popup" />

View file

@ -9,6 +9,7 @@
<string name="label_library">My library</string>
<string name="label_recent_updates">Recent updates</string>
<string name="label_catalogues">Catalogues</string>
<string name="label_categories">Categories</string>
<string name="label_selected">Selected: %1$d</string>
<!-- Actions -->