- Rewrote Category to Kotlin
- Moved category to ui - Reworked Animation (smoother) - Updated TextDrawable
@@ -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'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,11 +40,10 @@
 | 
			
		||||
            android:parentActivityName=".ui.main.MainActivity" >
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".ui.library.category.CategoryActivity"
 | 
			
		||||
            android:name=".ui.category.CategoryActivity"
 | 
			
		||||
            android:label="@string/label_categories"
 | 
			
		||||
            android:parentActivityName=".ui.main.MainActivity">
 | 
			
		||||
        </activity>
 | 
			
		||||
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".ui.setting.SettingsDownloadsFragment$CustomLayoutPickerActivity"
 | 
			
		||||
            android:label="@string/app_name"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,17 +6,17 @@ import javax.inject.Singleton;
 | 
			
		||||
 | 
			
		||||
import dagger.Component;
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadService;
 | 
			
		||||
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService;
 | 
			
		||||
import eu.kanade.tachiyomi.data.source.base.Source;
 | 
			
		||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService;
 | 
			
		||||
import eu.kanade.tachiyomi.data.mangasync.UpdateMangaSyncService;
 | 
			
		||||
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService;
 | 
			
		||||
import eu.kanade.tachiyomi.data.source.base.Source;
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.UpdateDownloader;
 | 
			
		||||
import eu.kanade.tachiyomi.injection.module.AppModule;
 | 
			
		||||
import eu.kanade.tachiyomi.injection.module.DataModule;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.catalogue.CataloguePresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.category.CategoryPresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.download.DownloadPresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.category.CategoryPresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaPresenter;
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersPresenter;
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
 | 
			
		||||
        return makeMovementFlags(dragFlags, swipeFlags);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
 | 
			
		||||
                          RecyclerView.ViewHolder target) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,276 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.category
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
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.Menu
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
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.library.LibraryCategoryAdapter
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_edit_categories.*
 | 
			
		||||
import kotlinx.android.synthetic.main.toolbar.*
 | 
			
		||||
import nucleus.factory.RequiresPresenter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Activity that shows categories.
 | 
			
		||||
 * Uses R.layout.activity_edit_categories.
 | 
			
		||||
 * UI related actions should be called from here.
 | 
			
		||||
 */
 | 
			
		||||
@RequiresPresenter(CategoryPresenter::class)
 | 
			
		||||
class CategoryActivity : BaseRxActivity<CategoryPresenter>(), 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<Category>) {
 | 
			
		||||
        destroyActionModeIfNeeded()
 | 
			
		||||
        adapter.setItems(categories)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete selected categories
 | 
			
		||||
     *
 | 
			
		||||
     * @param categories list containing categories
 | 
			
		||||
     */
 | 
			
		||||
    private fun deleteCategories(categories: List<Category?>?) {
 | 
			
		||||
        presenter.deleteCategories(categories)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the selected categories
 | 
			
		||||
     *
 | 
			
		||||
     * @return list of selected categories
 | 
			
		||||
     */
 | 
			
		||||
    private fun getSelectedCategories(): List<Category?>? {
 | 
			
		||||
        // 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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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<CategoryHolder, Category>(), 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<Category>) {
 | 
			
		||||
        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.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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<CategoryActivity>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to connect to database
 | 
			
		||||
     */
 | 
			
		||||
    @Inject lateinit var db: DatabaseHelper
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * List containing categories
 | 
			
		||||
     */
 | 
			
		||||
    private var categories: List<Category>? = 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<Category?>?) {
 | 
			
		||||
        db.deleteCategories(categories).asRxObservable().subscribe()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reorder categories in database
 | 
			
		||||
     *
 | 
			
		||||
     * @param categories list of categories
 | 
			
		||||
     */
 | 
			
		||||
    fun reorderCategories(categories: List<Category>) {
 | 
			
		||||
        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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<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;
 | 
			
		||||
 | 
			
		||||
    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<Category> categories) {
 | 
			
		||||
        destroyActionModeIfNeeded();
 | 
			
		||||
        adapter.setItems(categories);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private List<Category> 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<Category> 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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<CategoryHolder, Category> 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<Category> 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) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<CategoryActivity> {
 | 
			
		||||
 | 
			
		||||
    @Inject DatabaseHelper db;
 | 
			
		||||
 | 
			
		||||
    private List<Category> 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<Category> categories) {
 | 
			
		||||
        db.deleteCategories(categories).asRxObservable().subscribe();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void reorderCategories(List<Category> 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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-hdpi/ic_action_reorder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 327 B  | 
| 
		 Before Width: | Height: | Size: 116 B  | 
| 
		 Before Width: | Height: | Size: 148 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_action_reorder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 203 B  | 
| 
		 Before Width: | Height: | Size: 89 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xhdpi/ic_action_reorder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 368 B  | 
| 
		 Before Width: | Height: | Size: 114 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_action_reorder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 671 B  | 
| 
		 Before Width: | Height: | Size: 137 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxxhdpi/ic_action_reorder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 836 B  | 
| 
		 Before Width: | Height: | Size: 174 B  | 
@@ -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">
 | 
			
		||||
 | 
			
		||||
    <include layout="@layout/toolbar"/>
 | 
			
		||||
@@ -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"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.FloatingActionButton
 | 
			
		||||
        android:id="@+id/fab"
 | 
			
		||||
@@ -25,7 +27,7 @@
 | 
			
		||||
        android:scaleType="fitCenter"
 | 
			
		||||
        android:src="@drawable/ic_add_white_24dp"
 | 
			
		||||
        app:backgroundTint="@color/colorPrimary"
 | 
			
		||||
        app:layout_anchor="@id/categories_list"
 | 
			
		||||
        app:layout_anchor="@id/recycler"
 | 
			
		||||
        app:layout_anchorGravity="bottom|right|end"
 | 
			
		||||
        app:layout_behavior="eu.kanade.tachiyomi.ui.base.fab.FABAnimationUpDown"/>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
@@ -14,7 +14,6 @@
 | 
			
		||||
        android:layout_alignParentLeft="true"
 | 
			
		||||
        android:layout_alignParentStart="true"
 | 
			
		||||
        android:layout_centerInParent="true"
 | 
			
		||||
        android:elevation="4dp"
 | 
			
		||||
        android:clickable="true"
 | 
			
		||||
        android:layout_marginLeft="@dimen/margin_left"
 | 
			
		||||
        android:layout_marginStart="@dimen/margin_left"
 | 
			
		||||
@@ -30,8 +29,10 @@
 | 
			
		||||
        android:layout_marginRight="@dimen/margin_right"
 | 
			
		||||
        android:layout_marginEnd="@dimen/margin_right"
 | 
			
		||||
        android:scaleType="center"
 | 
			
		||||
        android:layout_centerInParent="true"
 | 
			
		||||
        android:layout_alignParentRight="true"
 | 
			
		||||
        android:src="@drawable/ic_reorder_grey_600_24dp"/>
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:src="@drawable/ic_action_reorder"/>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/title"
 | 
			
		||||
 
 | 
			
		||||