Allow to reorder and rename categories
This commit is contained in:
parent
e548cbf171
commit
3f1f9ea9f2
20 changed files with 280 additions and 20 deletions
|
@ -351,6 +351,7 @@ public class DatabaseHelper {
|
|||
.listOfObjects(Category.class)
|
||||
.withQuery(Query.builder()
|
||||
.table(CategoryTable.TABLE)
|
||||
.orderBy(CategoryTable.COLUMN_ORDER)
|
||||
.build())
|
||||
.prepare();
|
||||
}
|
||||
|
@ -361,6 +362,12 @@ public class DatabaseHelper {
|
|||
.prepare();
|
||||
}
|
||||
|
||||
public PreparedPutCollectionOfObjects<Category> insertCategories(List<Category> categories) {
|
||||
return db.put()
|
||||
.objects(categories)
|
||||
.prepare();
|
||||
}
|
||||
|
||||
public PreparedDeleteObject<Category> deleteCategory(Category category) {
|
||||
return db.delete()
|
||||
.object(category)
|
||||
|
|
|
@ -16,6 +16,12 @@ public class Category implements Serializable {
|
|||
@StorIOSQLiteColumn(name = CategoryTable.COLUMN_NAME)
|
||||
public String name;
|
||||
|
||||
@StorIOSQLiteColumn(name = CategoryTable.COLUMN_ORDER)
|
||||
public int order;
|
||||
|
||||
@StorIOSQLiteColumn(name = CategoryTable.COLUMN_FLAGS)
|
||||
public int flags;
|
||||
|
||||
public Category() {}
|
||||
|
||||
public static Category create(String name) {
|
||||
|
|
|
@ -13,6 +13,12 @@ public class CategoryTable {
|
|||
@NonNull
|
||||
public static final String COLUMN_NAME = "name";
|
||||
|
||||
@NonNull
|
||||
public static final String COLUMN_ORDER = "sort";
|
||||
|
||||
@NonNull
|
||||
public static final String COLUMN_FLAGS = "flags";
|
||||
|
||||
// This is just class with Meta Data, we don't need instances
|
||||
private CategoryTable() {
|
||||
throw new IllegalStateException("No instances please");
|
||||
|
@ -24,7 +30,9 @@ public class CategoryTable {
|
|||
public static String getCreateTableQuery() {
|
||||
return "CREATE TABLE " + TABLE + "("
|
||||
+ COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY, "
|
||||
+ COLUMN_NAME + " TEXT NOT NULL"
|
||||
+ COLUMN_NAME + " TEXT NOT NULL, "
|
||||
+ COLUMN_ORDER + " INTEGER NOT NULL, "
|
||||
+ COLUMN_FLAGS + " INTEGER NOT NULL"
|
||||
+ ");";
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Paul Burke
|
||||
*
|
||||
* 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.adapter;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
/**
|
||||
* Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public interface ItemTouchHelperAdapter {
|
||||
|
||||
/**
|
||||
* Called when an item has been dragged far enough to trigger a move. This is called every time
|
||||
* an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
|
||||
* adjusting the underlying data to reflect this move.
|
||||
*
|
||||
* @param fromPosition The start position of the moved item.
|
||||
* @param toPosition Then resolved position of the moved item.
|
||||
*
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemMove(int fromPosition, int toPosition);
|
||||
|
||||
|
||||
/**
|
||||
* Called when an item has been dismissed by a swipe.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
|
||||
* adjusting the underlying data to reflect this removal.
|
||||
*
|
||||
* @param position The position of the item dismissed.
|
||||
*
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemDismiss(int position);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.kanade.mangafeed.ui.base.adapter;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
public interface OnStartDragListener {
|
||||
|
||||
/**
|
||||
* Called when a view is requesting a start of a drag.
|
||||
*
|
||||
* @param viewHolder The holder of the view to drag.
|
||||
*/
|
||||
void onStartDrag(RecyclerView.ViewHolder viewHolder);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package eu.kanade.mangafeed.ui.base.adapter;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
private final ItemTouchHelperAdapter adapter;
|
||||
|
||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||
return makeMovementFlags(dragFlags, swipeFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
adapter.onItemDismiss(viewHolder.getAdapterPosition());
|
||||
}
|
||||
|
||||
}
|
|
@ -6,25 +6,29 @@ import android.view.ViewGroup;
|
|||
|
||||
import com.amulyakhare.textdrawable.util.ColorGenerator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.database.models.Category;
|
||||
import eu.kanade.mangafeed.ui.base.adapter.ItemTouchHelperAdapter;
|
||||
|
||||
public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> {
|
||||
public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> implements
|
||||
ItemTouchHelperAdapter {
|
||||
|
||||
private CategoryFragment fragment;
|
||||
private ColorGenerator generator;
|
||||
private final CategoryFragment fragment;
|
||||
private final ColorGenerator generator;
|
||||
|
||||
public CategoryAdapter(CategoryFragment fragment) {
|
||||
this.fragment = fragment;
|
||||
setHasStableIds(true);
|
||||
generator = ColorGenerator.DEFAULT;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public void setItems(List<Category> items) {
|
||||
mItems = items;
|
||||
mItems = new ArrayList<>(items);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
@ -42,7 +46,7 @@ public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> {
|
|||
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);
|
||||
return new CategoryHolder(v, this, fragment, fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,7 +58,23 @@ public class CategoryAdapter extends FlexibleAdapter<CategoryHolder, Category> {
|
|||
holder.itemView.setActivated(isSelected(position));
|
||||
}
|
||||
|
||||
public ColorGenerator getColorGenerator() {
|
||||
return generator;
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
if (fromPosition < toPosition) {
|
||||
for (int i = fromPosition; i < toPosition; i++) {
|
||||
Collections.swap(mItems, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = fromPosition; i > toPosition; i--) {
|
||||
Collections.swap(mItems, i, i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fragment.getPresenter().reorderCategories(mItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ 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.helper.ItemTouchHelper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
@ -22,6 +23,7 @@ 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.adapter.OnStartDragListener;
|
||||
import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment;
|
||||
import eu.kanade.mangafeed.ui.decoration.DividerItemDecoration;
|
||||
import eu.kanade.mangafeed.ui.library.LibraryCategoryAdapter;
|
||||
|
@ -29,14 +31,15 @@ import nucleus.factory.RequiresPresenter;
|
|||
import rx.Observable;
|
||||
|
||||
@RequiresPresenter(CategoryPresenter.class)
|
||||
public class CategoryFragment extends BaseRxFragment<CategoryPresenter>
|
||||
implements ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
|
||||
public class CategoryFragment extends BaseRxFragment<CategoryPresenter> implements
|
||||
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener, OnStartDragListener {
|
||||
|
||||
@Bind(R.id.categories_list) RecyclerView recycler;
|
||||
@Bind(R.id.fab) FloatingActionButton fab;
|
||||
|
||||
private CategoryAdapter adapter;
|
||||
private ActionMode actionMode;
|
||||
private ItemTouchHelper touchHelper;
|
||||
|
||||
public static CategoryFragment newInstance() {
|
||||
return new CategoryFragment();
|
||||
|
@ -56,12 +59,17 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter>
|
|||
recycler.addItemDecoration(new DividerItemDecoration(
|
||||
ResourcesCompat.getDrawable(getResources(), R.drawable.line_divider, null)));
|
||||
|
||||
// Touch helper to drag and reorder categories
|
||||
touchHelper = new ItemTouchHelper(new CategoryItemTouchHelper(adapter));
|
||||
touchHelper.attachToRecyclerView(recycler);
|
||||
|
||||
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();
|
||||
})
|
||||
.show();
|
||||
});
|
||||
|
||||
return view;
|
||||
|
@ -105,6 +113,8 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter>
|
|||
} else {
|
||||
setContextTitle(count);
|
||||
actionMode.invalidate();
|
||||
MenuItem editItem = actionMode.getMenu().findItem(R.id.action_edit);
|
||||
editItem.setVisible(count == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +138,10 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter>
|
|||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_delete:
|
||||
getPresenter().deleteCategories(getSelectedCategories());
|
||||
deleteCategories(getSelectedCategories());
|
||||
return true;
|
||||
case R.id.action_edit:
|
||||
editCategory(getSelectedCategories().get(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -147,4 +160,22 @@ public class CategoryFragment extends BaseRxFragment<CategoryPresenter>
|
|||
}
|
||||
}
|
||||
|
||||
private void deleteCategories(List<Category> categories) {
|
||||
getPresenter().deleteCategories(categories);
|
||||
}
|
||||
|
||||
private void editCategory(Category category) {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.action_rename_category)
|
||||
.input(getString(R.string.name), category.name, false, (dialog, input) -> {
|
||||
getPresenter().renameCategory(category, input.toString());
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
|
||||
touchHelper.startDrag(viewHolder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eu.kanade.mangafeed.ui.library.category;
|
||||
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
@ -13,6 +15,7 @@ import butterknife.OnClick;
|
|||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.database.models.Category;
|
||||
import eu.kanade.mangafeed.ui.base.adapter.FlexibleViewHolder;
|
||||
import eu.kanade.mangafeed.ui.base.adapter.OnStartDragListener;
|
||||
|
||||
public class CategoryHolder extends FlexibleViewHolder {
|
||||
|
||||
|
@ -20,11 +23,21 @@ public class CategoryHolder extends FlexibleViewHolder {
|
|||
|
||||
@Bind(R.id.image) ImageView image;
|
||||
@Bind(R.id.title) TextView title;
|
||||
@Bind(R.id.reorder) ImageView reorder;
|
||||
|
||||
public CategoryHolder(View view, CategoryAdapter adapter, OnListItemClickListener listener) {
|
||||
public CategoryHolder(View view, CategoryAdapter adapter,
|
||||
OnListItemClickListener listener, OnStartDragListener dragListener) {
|
||||
super(view, adapter, listener);
|
||||
ButterKnife.bind(this, view);
|
||||
this.view = view;
|
||||
|
||||
reorder.setOnTouchListener((v, event) -> {
|
||||
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
|
||||
dragListener.onStartDrag(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public void onSetValues(Category category, ColorGenerator generator) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package eu.kanade.mangafeed.ui.library.category;
|
||||
|
||||
import eu.kanade.mangafeed.ui.base.adapter.ItemTouchHelperAdapter;
|
||||
import eu.kanade.mangafeed.ui.base.adapter.SimpleItemTouchHelperCallback;
|
||||
|
||||
public class CategoryItemTouchHelper extends SimpleItemTouchHelperCallback {
|
||||
|
||||
public CategoryItemTouchHelper(ItemTouchHelperAdapter adapter) {
|
||||
super(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@ public class CategoryPresenter extends BasePresenter<CategoryFragment> {
|
|||
|
||||
@Inject DatabaseHelper db;
|
||||
|
||||
private List<Category> categories;
|
||||
|
||||
private static final int GET_CATEGORIES = 1;
|
||||
|
||||
@Override
|
||||
|
@ -23,6 +25,7 @@ public class CategoryPresenter extends BasePresenter<CategoryFragment> {
|
|||
|
||||
restartableLatestCache(GET_CATEGORIES,
|
||||
() -> db.getCategories().createObservable()
|
||||
.doOnNext(categories -> this.categories = categories)
|
||||
.observeOn(AndroidSchedulers.mainThread()),
|
||||
CategoryFragment::setCategories);
|
||||
|
||||
|
@ -30,10 +33,36 @@ public class CategoryPresenter extends BasePresenter<CategoryFragment> {
|
|||
}
|
||||
|
||||
public void createCategory(String name) {
|
||||
db.insertCategory(Category.create(name)).createObservable().subscribe();
|
||||
Category cat = Category.create(name);
|
||||
|
||||
// Set the new item in the last position
|
||||
int max = 0;
|
||||
if (categories != null) {
|
||||
for (Category cat2 : categories) {
|
||||
if (cat2.order > max) {
|
||||
max = cat2.order + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
cat.order = max;
|
||||
|
||||
db.insertCategory(cat).createObservable().subscribe();
|
||||
}
|
||||
|
||||
public void deleteCategories(List<Category> categories) {
|
||||
db.deleteCategories(categories).createObservable().subscribe();
|
||||
}
|
||||
|
||||
public void reorderCategories(List<Category> categories) {
|
||||
for (int i = 0; i < categories.size(); i++) {
|
||||
categories.get(i).order = i;
|
||||
}
|
||||
|
||||
db.insertCategories(categories).createObservable().subscribe();
|
||||
}
|
||||
|
||||
public void renameCategory(Category category, String name) {
|
||||
category.name = name;
|
||||
db.insertCategory(category).createObservable().subscribe();
|
||||
}
|
||||
}
|
||||
|
|
BIN
app/src/main/res/drawable-hdpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 116 B |
BIN
app/src/main/res/drawable-ldpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-ldpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 B |
BIN
app/src/main/res/drawable-mdpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 B |
BIN
app/src/main/res/drawable-xhdpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 137 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_reorder_grey_600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_reorder_grey_600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 B |
|
@ -21,14 +21,26 @@
|
|||
android:layout_marginRight="@dimen/margin_right"
|
||||
android:layout_marginEnd="@dimen/margin_right"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reorder"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginLeft="@dimen/margin_left"
|
||||
android:layout_marginStart="@dimen/margin_left"
|
||||
android:layout_marginRight="@dimen/margin_right"
|
||||
android:layout_marginEnd="@dimen/margin_right"
|
||||
android:scaleType="center"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/ic_reorder_grey_600_24dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="@dimen/margin_right"
|
||||
android:layout_marginEnd="@dimen/margin_right"
|
||||
android:layout_toRightOf="@id/image"
|
||||
android:layout_toEndOf="@id/image"
|
||||
android:layout_toLeftOf="@id/reorder"
|
||||
android:layout_toStartOf="@id/reorder"
|
||||
android:layout_centerInParent="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:id="@+id/action_edit"
|
||||
android:title="@string/action_edit"
|
||||
android:icon="@drawable/ic_create"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item android:id="@+id/action_delete"
|
||||
android:title="@string/action_delete"
|
||||
android:icon="@drawable/ic_action_delete"
|
||||
android:orderInCategory="1"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
</menu>
|
|
@ -24,6 +24,7 @@
|
|||
<string name="action_edit">Edit</string>
|
||||
<string name="action_add_category">Add category</string>
|
||||
<string name="action_edit_categories">Edit categories</string>
|
||||
<string name="action_rename_category">Rename category</string>
|
||||
<string name="action_sort_up">Sort up</string>
|
||||
<string name="action_sort_down">Sort down</string>
|
||||
<string name="action_show_unread">Unread</string>
|
||||
|
|
Reference in a new issue