From 9f78c8f6b4606b407332501a2765cff9d878e2f4 Mon Sep 17 00:00:00 2001 From: NoodleMage Date: Wed, 24 Feb 2016 11:48:21 +0100 Subject: [PATCH] - Rewrote Category to Kotlin - Moved category to ui - Reworked Animation (smoother) - Updated TextDrawable --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 3 +- .../injection/component/AppComponent.java | 6 +- .../SimpleItemTouchHelperCallback.java | 1 + .../tachiyomi/ui/category/CategoryActivity.kt | 276 ++++++++++++++++++ .../tachiyomi/ui/category/CategoryAdapter.kt | 110 +++++++ .../tachiyomi/ui/category/CategoryHolder.kt | 74 +++++ .../ui/category/CategoryItemTouchHelper.kt | 26 ++ .../ui/category/CategoryPresenter.kt | 106 +++++++ .../tachiyomi/ui/library/LibraryFragment.java | 2 +- .../ui/library/category/CategoryActivity.java | 180 ------------ .../ui/library/category/CategoryAdapter.java | 80 ----- .../ui/library/category/CategoryHolder.java | 58 ---- .../category/CategoryItemTouchHelper.java | 16 - .../library/category/CategoryPresenter.java | 68 ----- .../tachiyomi/util/ViewGroupExtensions.kt | 15 + .../res/drawable-hdpi/ic_action_reorder.png | Bin 0 -> 327 bytes .../ic_reorder_grey_600_24dp.png | Bin 116 -> 0 bytes .../ic_reorder_grey_600_24dp.png | Bin 148 -> 0 bytes .../res/drawable-mdpi/ic_action_reorder.png | Bin 0 -> 203 bytes .../ic_reorder_grey_600_24dp.png | Bin 89 -> 0 bytes .../res/drawable-xhdpi/ic_action_reorder.png | Bin 0 -> 368 bytes .../ic_reorder_grey_600_24dp.png | Bin 114 -> 0 bytes .../res/drawable-xxhdpi/ic_action_reorder.png | Bin 0 -> 671 bytes .../ic_reorder_grey_600_24dp.png | Bin 137 -> 0 bytes .../drawable-xxxhdpi/ic_action_reorder.png | Bin 0 -> 836 bytes .../ic_reorder_grey_600_24dp.png | Bin 174 -> 0 bytes .../res/layout/activity_edit_categories.xml | 8 +- .../main/res/layout/item_edit_categories.xml | 9 +- 29 files changed, 624 insertions(+), 415 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItemTouchHelper.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryActivity.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryAdapter.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryHolder.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryItemTouchHelper.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryPresenter.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt create mode 100644 app/src/main/res/drawable-hdpi/ic_action_reorder.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_reorder_grey_600_24dp.png delete mode 100644 app/src/main/res/drawable-ldpi/ic_reorder_grey_600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_reorder.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_reorder_grey_600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_reorder.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_reorder_grey_600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_reorder.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_reorder_grey_600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_reorder.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_reorder_grey_600_24dp.png diff --git a/app/build.gradle b/app/build.gradle index 3ad59e14e..fe215f29f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ import java.text.SimpleDateFormat apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' apply plugin: 'com.neenbedankt.android-apt' apply plugin: 'me.tatarka.retrolambda' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ed8a82fa7..2c5fc5bfc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,11 +40,10 @@ android:parentActivityName=".ui.main.MainActivity" > - (), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener, OnStartDragListener { + + /** + * Object used to show actionMode toolbar. + */ + var actionMode: ActionMode? = null + + /** + * Adapter containing category items. + */ + private lateinit var adapter: CategoryAdapter + + /** + * TouchHelper used for reorder animation and movement. + */ + private lateinit var touchHelper: ItemTouchHelper + + companion object { + /** + * Create new CategoryActivity intent. + * + * @param context context information. + */ + @JvmStatic + fun newIntent(context: Context): Intent? { + return Intent(context, CategoryActivity::class.java) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Inflate activity_edit_categories.xml. + setContentView(R.layout.activity_edit_categories) + + // Setup the toolbar. + setupToolbar(toolbar) + + // Get new adapter. + adapter = CategoryAdapter(this) + + // Create view and inject category items into view + recycler.layoutManager = LinearLayoutManager(this) + recycler.setHasFixedSize(true) + recycler.adapter = adapter + + // Touch helper to drag and reorder categories + touchHelper = ItemTouchHelper(CategoryItemTouchHelper(adapter)) + touchHelper.attachToRecyclerView(recycler) + + // Create OnClickListener for creating new category + fab.setOnClickListener({ v -> + MaterialDialog.Builder(this) + .title(R.string.action_add_category) + .negativeText(R.string.button_cancel) + .input(R.string.name, 0, false) + { dialog, input -> presenter.createCategory(input.toString()) } + .show() + }) + } + + /** + * Finishes action mode. + * Call this when action mode action is finished. + */ + fun destroyActionModeIfNeeded() { + actionMode?.finish() + } + + /** + * Fill adapter with category items + * + * @param categories list containing categories + */ + fun setCategories(categories: List) { + destroyActionModeIfNeeded() + adapter.setItems(categories) + } + + /** + * Delete selected categories + * + * @param categories list containing categories + */ + private fun deleteCategories(categories: List?) { + presenter.deleteCategories(categories) + } + + /** + * Returns the selected categories + * + * @return list of selected categories + */ + private fun getSelectedCategories(): List? { + // Create a list of the selected categories + return adapter.selectedItems.map { adapter.getItem(it) } + } + + /** + * Show MaterialDialog which let user change category name. + * + * @param category category that will be edited. + */ + private fun editCategory(category: Category?) { + MaterialDialog.Builder(this) + .title(R.string.action_rename_category) + .negativeText(R.string.button_cancel) + .onNegative { materialDialog, dialogAction -> destroyActionModeIfNeeded() } + .input(getString(R.string.name), category?.name, false) + { dialog, input -> presenter.renameCategory(category as Category, input.toString()) } + .show() + } + + /** + * Toggle actionMode selection + * + * @param position position of selected item + */ + private fun toggleSelection(position: Int) { + adapter.toggleSelection(position, false) + + // Get selected item count + val count = adapter.selectedItemCount + + // If no item is selected finish action mode + if (count == 0) { + actionMode?.finish() + } else { + // This block will only run if actionMode is not null + actionMode?.let { + + // Set title equal to selected item + it.title = getString(R.string.label_selected, count) + it.invalidate() + + // Show edit button only when one item is selected + val editItem = it.menu?.findItem(R.id.action_edit) + editItem?.isVisible = count == 1 + } + } + } + + /** + * Called each time the action mode is shown. + * Always called after onCreateActionMode + * + * @return false + */ + override fun onPrepareActionMode(p0: ActionMode?, p1: Menu?): Boolean { + return false + } + + /** + * Called when action mode item clicked. + * + * @param actionMode action mode toolbar. + * @param menuItem selected menu item. + * + * @return action mode item clicked exist status + */ + override fun onActionItemClicked(actionMode: ActionMode, menuItem: MenuItem): Boolean { + when (menuItem.itemId) { + R.id.action_delete -> { + // Delete select categories. + deleteCategories(getSelectedCategories()) + return true + } + R.id.action_edit -> { + // Edit selected category + editCategory(getSelectedCategories()?.get(0)) + return true + } + } + return false + } + + /** + * Inflate menu when action mode selected. + * + * @param mode ActionMode object + * @param menu Menu object + * + * @return true + */ + override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { + // Inflate menu. + mode.menuInflater.inflate(R.menu.category_selection, menu) + // Enable adapter multi selection. + adapter.mode = LibraryCategoryAdapter.MODE_MULTI + return true + } + + /** + * Called when action mode destroyed. + * + * @param mode ActionMode object. + */ + override fun onDestroyActionMode(mode: ActionMode?) { + // Reset adapter to single selection + adapter.mode = LibraryCategoryAdapter.MODE_SINGLE + // Clear selected items + adapter.clearSelection() + actionMode = null + } + + /** + * Called when item in list is clicked. + * + * @param position position of clicked item. + */ + override fun onListItemClick(position: Int): Boolean { + // Check if action mode is initialized and selected item exist. + if (actionMode != null && position != -1) { + // Toggle selection of clicked item. + toggleSelection(position) + return true + } else { + return false + } + } + + /** + * Called when item long clicked + * + * @param position position of clicked item. + */ + override fun onListItemLongClick(position: Int) { + // Check if action mode is initialized. + if (actionMode == null) + // Initialize action mode + actionMode = startSupportActionMode(this) + + // Set item as selected + toggleSelection(position) + } + + /** + * Called when item is dragged + * + * @param viewHolder view that contains dragged item + */ + override fun onStartDrag(viewHolder: RecyclerView.ViewHolder?) { + // Notify touchHelper + touchHelper.startDrag(viewHolder) + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt new file mode 100644 index 000000000..a377276a1 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt @@ -0,0 +1,110 @@ +package eu.kanade.tachiyomi.ui.category + +import android.view.ViewGroup +import com.amulyakhare.textdrawable.util.ColorGenerator +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.ui.base.adapter.ItemTouchHelperAdapter +import eu.kanade.tachiyomi.util.inflate +import java.util.* + +/** + * Adapter of CategoryHolder. + * Connection between Activity and Holder + * Holder updates should be called from here. + * + * @param activity activity that created adapter + * @constructor Creates a CategoryAdapter object + */ +class CategoryAdapter(private val activity: CategoryActivity) : FlexibleAdapter(), ItemTouchHelperAdapter { + + /** + * Generator used to generate circle letter icons + */ + private val generator: ColorGenerator + + init { + // Let generator use Material Design colors. + // Material design is love, material design is live! + generator = ColorGenerator.MATERIAL + + // Set unique id's + setHasStableIds(true) + } + + /** + * Called when ViewHolder is created + * + * @param parent parent View + * @param viewType int containing viewType + */ + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryHolder { + // Inflate layout with item_edit_categories.xml + val view = parent.inflate(R.layout.item_edit_categories) + return CategoryHolder(view, this, activity, activity) + } + + /** + * Called when ViewHolder is bind + * + * @param holder bind holder + * @param position position of holder + */ + override fun onBindViewHolder(holder: CategoryHolder, position: Int) { + // Update holder values. + val category = getItem(position) + holder.onSetValues(category, generator) + + //When user scrolls this bind the correct selection status + holder.itemView.isActivated = isSelected(position) + } + + /** + * Update items with list of categories + * + * @param items list of categories + */ + fun setItems(items: List) { + mItems = ArrayList(items) + notifyDataSetChanged() + } + + /** + * Get category by position + * + * @param position position of item + */ + override fun getItemId(position: Int): Long { + return mItems[position].id!!.toLong() + } + + /** + * Called when item is moved + * + * @param fromPosition previous position of item. + * @param toPosition new position of item. + */ + override fun onItemMove(fromPosition: Int, toPosition: Int) { + // Move items and notify touch helper + Collections.swap(mItems, fromPosition, toPosition) + notifyItemMoved(fromPosition, toPosition) + + // Update database + activity.presenter.reorderCategories(mItems) + } + + /** + * Must be implemented, not used + */ + override fun onItemDismiss(position: Int) { + // Empty method. + } + + /** + * Must be implemented, not used + */ + override fun updateDataSet(p0: String?) { + // Empty method. + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt new file mode 100644 index 000000000..f4cce6540 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt @@ -0,0 +1,74 @@ +package eu.kanade.tachiyomi.ui.category + +import android.graphics.Color +import android.graphics.Typeface +import android.support.v4.view.MotionEventCompat +import android.view.MotionEvent +import android.view.View +import com.amulyakhare.textdrawable.TextDrawable +import com.amulyakhare.textdrawable.util.ColorGenerator +import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder +import eu.kanade.tachiyomi.ui.base.adapter.OnStartDragListener +import kotlinx.android.synthetic.main.item_edit_categories.view.* + +/** + * Holder that contains category item. + * Uses R.layout.item_edit_categories. + * UI related actions should be called from here. + * + * @param view view of category item. + * @param adapter adapter belonging to holder. + * @param listener called when item clicked. + * @param dragListener called when item dragged. + * + * @constructor Create CategoryHolder object + */ +class CategoryHolder(view: View, adapter: CategoryAdapter, listener: FlexibleViewHolder.OnListItemClickListener, dragListener: OnStartDragListener) : FlexibleViewHolder(view, adapter, listener) { + + init { + // Create round letter image onclick to simulate long click + itemView.image.setOnClickListener({ v -> + // Simulate long click on this view to enter selection mode + onLongClick(view) + }) + + // Set on touch listener for reorder image + itemView.reorder.setOnTouchListener({ v, event -> + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + dragListener.onStartDrag(this) + } + false + }) + } + + /** + * Update category item values. + * + * @param category category of item. + * @param generator generator used to generate circle letter icons. + */ + fun onSetValues(category: Category, generator: ColorGenerator) { + // Set capitalized title. + itemView.title.text = category.name.capitalize() + + // Update circle letter image. + itemView.image.setImageDrawable(getRound(category.name.substring(0, 1).toUpperCase(), generator)) + } + + /** + * Returns circle letter image + * + * @param text first letter of string + * @param generator the generator used to generate circle letter image + */ + private fun getRound(text: String, generator: ColorGenerator): TextDrawable { + return TextDrawable.builder() + .beginConfig() + .textColor(Color.WHITE) + .useFont(Typeface.DEFAULT) + .toUpperCase() + .endConfig() + .buildRound(text, generator.getColor(text)) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItemTouchHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItemTouchHelper.kt new file mode 100644 index 000000000..1e1ad8df3 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItemTouchHelper.kt @@ -0,0 +1,26 @@ +package eu.kanade.tachiyomi.ui.category + +import eu.kanade.tachiyomi.ui.base.adapter.ItemTouchHelperAdapter +import eu.kanade.tachiyomi.ui.base.adapter.SimpleItemTouchHelperCallback + +class CategoryItemTouchHelper(adapter: ItemTouchHelperAdapter) : SimpleItemTouchHelperCallback(adapter) { + + /** + * Disable items swipe remove + * + * @return false + */ + override fun isItemViewSwipeEnabled(): Boolean { + return false + } + + /** + * Disable long press item drag + * + * @return false + */ + override fun isLongPressDragEnabled(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt new file mode 100644 index 000000000..9a67159eb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt @@ -0,0 +1,106 @@ +package eu.kanade.tachiyomi.ui.category + +import android.os.Bundle +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter +import rx.android.schedulers.AndroidSchedulers +import javax.inject.Inject + +/** + * Presenter of CategoryActivity. + * Contains information and data for activity. + * Observable updates should be called from here. + */ +class CategoryPresenter : BasePresenter() { + + /** + * Used to connect to database + */ + @Inject lateinit var db: DatabaseHelper + + /** + * List containing categories + */ + private var categories: List? = null + + companion object { + /** + * The id of the restartable. + */ + final private val GET_CATEGORIES = 1 + } + + override fun onCreate(savedState: Bundle?) { + super.onCreate(savedState) + + // Get categories as list + restartableLatestCache(GET_CATEGORIES, + { + db.categories.asRxObservable() + .doOnNext { categories -> this.categories = categories } + .observeOn(AndroidSchedulers.mainThread()) + }, CategoryActivity::setCategories) + + // Start get categories as list task + start(GET_CATEGORIES) + } + + + /** + * Create category and add it to database + * + * @param name name of category + */ + fun createCategory(name: String) { + // Create category. + val cat = Category.create(name) + + // Set the new item in the last position. + var max = 0 + if (categories != null) { + for (cat2 in categories!!) { + if (cat2.order > max) { + max = cat2.order + 1 + } + } + } + cat.order = max + + // Insert into database. + db.insertCategory(cat).asRxObservable().subscribe() + } + + /** + * Delete category from database + * + * @param categories list of categories + */ + fun deleteCategories(categories: List?) { + db.deleteCategories(categories).asRxObservable().subscribe() + } + + /** + * Reorder categories in database + * + * @param categories list of categories + */ + fun reorderCategories(categories: List) { + for (i in categories.indices) { + categories[i].order = i + } + + db.insertCategories(categories).asRxObservable().subscribe() + } + + /** + * Rename a category + * + * @param category category that gets renamed + * @param name new name of category + */ + fun renameCategory(category: Category, name: String) { + category.name = name + db.insertCategory(category).asRxObservable().subscribe() + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.java index 217600448..e397f2045 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.java @@ -38,7 +38,7 @@ import eu.kanade.tachiyomi.data.io.IOHandler; import eu.kanade.tachiyomi.data.library.LibraryUpdateService; import eu.kanade.tachiyomi.event.LibraryMangasEvent; import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment; -import eu.kanade.tachiyomi.ui.library.category.CategoryActivity; +import eu.kanade.tachiyomi.ui.category.CategoryActivity; import eu.kanade.tachiyomi.ui.main.MainActivity; import eu.kanade.tachiyomi.util.ToastUtil; import icepick.State; diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryActivity.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryActivity.java deleted file mode 100644 index b5409cde5..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryActivity.java +++ /dev/null @@ -1,180 +0,0 @@ -package eu.kanade.tachiyomi.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.Menu; -import android.view.MenuItem; - -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.Category; -import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity; -import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder; -import eu.kanade.tachiyomi.ui.base.adapter.OnStartDragListener; -import eu.kanade.tachiyomi.ui.decoration.DividerItemDecoration; -import eu.kanade.tachiyomi.ui.library.LibraryCategoryAdapter; -import nucleus.factory.RequiresPresenter; -import rx.Observable; - -@RequiresPresenter(CategoryPresenter.class) -public class CategoryActivity extends BaseRxActivity 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; - - private CategoryAdapter adapter; - private ActionMode actionMode; - private ItemTouchHelper touchHelper; - - public static Intent newIntent(Context context) { - return new Intent(context, CategoryActivity.class); - } - - @Override - protected void onCreate(Bundle savedState) { - super.onCreate(savedState); - setContentView(R.layout.activity_edit_categories); - ButterKnife.bind(this); - - setupToolbar(toolbar); - - adapter = new CategoryAdapter(this); - recycler.setLayoutManager(new LinearLayoutManager(this)); - recycler.setHasFixedSize(true); - recycler.setAdapter(adapter); - 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(this) - .title(R.string.action_add_category) - .input(R.string.name, 0, false, (dialog, input) -> { - getPresenter().createCategory(input.toString()); - }) - .show(); - }); - } - - 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 = 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(); - MenuItem editItem = actionMode.getMenu().findItem(R.id.action_edit); - editItem.setVisible(count == 1); - } - } - - 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: - deleteCategories(getSelectedCategories()); - return true; - case R.id.action_edit: - editCategory(getSelectedCategories().get(0)); - 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(); - } - } - - private void deleteCategories(List categories) { - getPresenter().deleteCategories(categories); - } - - private void editCategory(Category category) { - 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()); - }) - .show(); - } - - @Override - public void onStartDrag(RecyclerView.ViewHolder viewHolder) { - touchHelper.startDrag(viewHolder); - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryAdapter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryAdapter.java deleted file mode 100644 index e1a845385..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryAdapter.java +++ /dev/null @@ -1,80 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.category; - -import android.view.LayoutInflater; -import android.view.View; -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.tachiyomi.R; -import eu.kanade.tachiyomi.data.database.models.Category; -import eu.kanade.tachiyomi.ui.base.adapter.ItemTouchHelperAdapter; - -public class CategoryAdapter extends FlexibleAdapter implements - ItemTouchHelperAdapter { - - private final CategoryActivity activity; - private final ColorGenerator generator; - - public CategoryAdapter(CategoryActivity activity) { - this.activity = activity; - generator = ColorGenerator.DEFAULT; - setHasStableIds(true); - } - - public void setItems(List items) { - mItems = new ArrayList<>(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 = activity.getLayoutInflater(); - View v = inflater.inflate(R.layout.item_edit_categories, parent, false); - return new CategoryHolder(v, this, activity, activity); - } - - @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)); - } - - @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); - } - } - - activity.getPresenter().reorderCategories(mItems); - } - - @Override - public void onItemDismiss(int position) { - - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryHolder.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryHolder.java deleted file mode 100644 index feec63a71..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryHolder.java +++ /dev/null @@ -1,58 +0,0 @@ -package eu.kanade.tachiyomi.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; - -import com.amulyakhare.textdrawable.TextDrawable; -import com.amulyakhare.textdrawable.util.ColorGenerator; - -import butterknife.Bind; -import butterknife.ButterKnife; -import butterknife.OnClick; -import eu.kanade.tachiyomi.R; -import eu.kanade.tachiyomi.data.database.models.Category; -import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder; -import eu.kanade.tachiyomi.ui.base.adapter.OnStartDragListener; - -public class CategoryHolder extends FlexibleViewHolder { - - private View view; - - @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, 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) { - 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/tachiyomi/ui/library/category/CategoryItemTouchHelper.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryItemTouchHelper.java deleted file mode 100644 index 7e38a25de..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryItemTouchHelper.java +++ /dev/null @@ -1,16 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.category; - -import eu.kanade.tachiyomi.ui.base.adapter.ItemTouchHelperAdapter; -import eu.kanade.tachiyomi.ui.base.adapter.SimpleItemTouchHelperCallback; - -public class CategoryItemTouchHelper extends SimpleItemTouchHelperCallback { - - public CategoryItemTouchHelper(ItemTouchHelperAdapter adapter) { - super(adapter); - } - - @Override - public boolean isItemViewSwipeEnabled() { - return false; - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryPresenter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryPresenter.java deleted file mode 100644 index edb305c9a..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/category/CategoryPresenter.java +++ /dev/null @@ -1,68 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.category; - -import android.os.Bundle; - -import java.util.List; - -import javax.inject.Inject; - -import eu.kanade.tachiyomi.data.database.DatabaseHelper; -import eu.kanade.tachiyomi.data.database.models.Category; -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter; -import rx.android.schedulers.AndroidSchedulers; - -public class CategoryPresenter extends BasePresenter { - - @Inject DatabaseHelper db; - - private List categories; - - private static final int GET_CATEGORIES = 1; - - @Override - protected void onCreate(Bundle savedState) { - super.onCreate(savedState); - - restartableLatestCache(GET_CATEGORIES, - () -> db.getCategories().asRxObservable() - .doOnNext(categories -> this.categories = categories) - .observeOn(AndroidSchedulers.mainThread()), - CategoryActivity::setCategories); - - start(GET_CATEGORIES); - } - - public void createCategory(String name) { - 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).asRxObservable().subscribe(); - } - - public void deleteCategories(List categories) { - db.deleteCategories(categories).asRxObservable().subscribe(); - } - - public void reorderCategories(List categories) { - for (int i = 0; i < categories.size(); i++) { - categories.get(i).order = i; - } - - db.insertCategories(categories).asRxObservable().subscribe(); - } - - public void renameCategory(Category category, String name) { - category.name = name; - db.insertCategory(category).asRxObservable().subscribe(); - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt new file mode 100644 index 000000000..377fd1bf5 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt @@ -0,0 +1,15 @@ +package eu.kanade.tachiyomi.util + +import android.support.annotation.LayoutRes +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +/** + * Extension method to inflate a view directly from its parent. + * @param layout the layout to inflate. + * @param attachToRoot whether to attach the view to the root or not. Defaults to false. + */ +fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false): View { + return LayoutInflater.from(context).inflate(layout, this, attachToRoot) +} \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_action_reorder.png b/app/src/main/res/drawable-hdpi/ic_action_reorder.png new file mode 100644 index 0000000000000000000000000000000000000000..9aa1825a0d602c46976e5ef98732f9dc320d8398 GIT binary patch literal 327 zcmV-N0l5B&P)%(v)V{WEy+GL*}a8>dnXQI2zTZH zk?suW*EtY|aAyt>>CS*sT11*icjf?*R)KEYHXg?@syfU3Fbw-NO}j;VY21X@bzN$$ zFV7NpwdZ-h=XqZ4&i|U@VAZ{JkyZ_AJ@1Zm>jTvH-3OMpHETp=vsJ~&;ZX=x!|>L@L(I#vpQh#NeMC84ENUbM98m@rRE3ugW8M?AxuO(pKq zYP!AQaSk?^7D@u)P`C`sLfBwhC<%l^;W8`>VS{O*BoGdT%djkj4W@;XKsXdG!?NiJ Ze*l1dfIX7EcyRy#002ovPDHLkV1nXohkO74 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_reorder_grey_600_24dp.png b/app/src/main/res/drawable-hdpi/ic_reorder_grey_600_24dp.png deleted file mode 100644 index 29a4975ffe7d8fbe430c16524eacc731b78601a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;wWo_?NX4yWjnoBvDH5g`9@0+& zZaJ`(957k2@Qc0VhQ>Cwz_ZzlH=0SoiISw;D+;ruSr~R(OkSsKy)6!C41=eupUXO@ GgeCx$CL(zN diff --git a/app/src/main/res/drawable-ldpi/ic_reorder_grey_600_24dp.png b/app/src/main/res/drawable-ldpi/ic_reorder_grey_600_24dp.png deleted file mode 100644 index b5d38304b26a57577445286c2d327a9a3e3d624b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a)4Xipc%kcwN$2@32VK7QQDWXR5V zhU>aP@-d#(p{v7=G8HoM$#4fTU*AyjGH7?~?lRT)H#RDZO0%78yrPi3ft5?GQDuAn w{drA23#BGGWU=jJyJX{Av|*A=;SvUhqmPfN+FjI`3bcm7)78&qol`;+0KuU$1^@s6 diff --git a/app/src/main/res/drawable-mdpi/ic_action_reorder.png b/app/src/main/res/drawable-mdpi/ic_action_reorder.png new file mode 100644 index 0000000000000000000000000000000000000000..9a7eab26fd65ba42cdf2a803e20513ed0bf49a0c GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dElRRAKL*A=mTP?mdKI;Vst0P)*>8~^|S literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_reorder_grey_600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_reorder_grey_600_24dp.png deleted file mode 100644 index f36c169968100303b4f8b69cd757c3ed39fd5519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tOHUWakcwMxFCXM&FyLV})SvtF zwyc*F2M7Ox^OjThb2Bi^VDr1o@V>$4FM~p`J;RAB{0v5{3}(#Y%PvPte@Jk!1{%WP M>FVdQ&MBb@00Sr2PsjN@A0+N--|G1E^^>vhgX}7+!+Sa8;+dK_<s0-bx0iEY^6yIz;&({ZY)_S{IUd&hfAiG`yLGEwn%^J$Y;^Fk zwF8QqzIU+wHh!6Rnqyz`>kAJr6z+)K@1OlaG5LSahx2WRzy7L>YUURN3dH!^uQ-@; zN3i0E`>Lmu_h)Q~{&IJkV9oJsy0>(H73{vV=>5Z8DLY-~=g)lq!1;(& z4afD%c^Bn3GWY-J_{VW+sUoLdqyJH%IZCmo6nC)LiT>s|n0K*!7trCa#omh5?ugC1 z_`M)@)15`@f|qz(4l;$G#V37DsI+=7vk{o^7(8A5T-G@yGywnr CDlka^ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_reorder_grey_600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_reorder_grey_600_24dp.png deleted file mode 100644 index 4c72a14290abb60cdd4d7c4ae2da53dd9f818522..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw0z6$DLn>~)y?T(7fq{d0qu$#; zyIMKg^d^MsPmSgl0D}w80s4F#FVs))GcsmM3QU-0>87Ay&%&}K)xja^nM7m579I{T dc%hNOaOa9Iv-IrV}O$t10oAP##}^kE|OM(1K^-lS7=~Z1`2FzMn)e-sr#V`cU-@$ z`!kOXXLQ-|E$Ge=zxXnn8%ZmR0XXJ3ITRYeap~v45ZrLATvVc5aIg0M<&1+jA}LCj Z@!yU$EcDuC!Vk~)y?&6B!GMR^P=D^v z+p1m}O&?gQWc^aVF#(kzzz3-UJ82NtLEoX15lH`GRAmEFAK0fz0I37=0ZBlLp&pwg eNCFHJ*dH+cPtU1nurinr67Y2Ob6Mw<&;$TJMJAO1 diff --git a/app/src/main/res/layout/activity_edit_categories.xml b/app/src/main/res/layout/activity_edit_categories.xml index d9799cdff..5f044468f 100644 --- a/app/src/main/res/layout/activity_edit_categories.xml +++ b/app/src/main/res/layout/activity_edit_categories.xml @@ -4,6 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:gravity="center"> @@ -12,9 +13,10 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="?attr/actionBarSize" - android:id="@+id/categories_list" + android:id="@+id/recycler" android:choiceMode="multipleChoice" - android:listSelector="@color/list_choice_pressed_bg_light" /> + android:listSelector="@color/list_choice_pressed_bg_light" + tools:listitem="@layout/item_edit_categories"/> diff --git a/app/src/main/res/layout/item_edit_categories.xml b/app/src/main/res/layout/item_edit_categories.xml index 97457cf7a..a4b1a6c3d 100644 --- a/app/src/main/res/layout/item_edit_categories.xml +++ b/app/src/main/res/layout/item_edit_categories.xml @@ -3,8 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightLarge" - android:paddingTop="@dimen/margin_top" - android:paddingBottom="@dimen/margin_bottom" + android:paddingTop="8dp" + android:paddingBottom="8dp" android:background="@drawable/selector_chapter_light"> + android:layout_alignParentEnd="true" + android:src="@drawable/ic_action_reorder"/>