Bläddra i källkod

Change filters dialog with a drawer

len 8 år sedan
förälder
incheckning
c25af3d5ad

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt

@@ -343,7 +343,6 @@ class Batoto(override val id: Int) : ParsedOnlineSource(), LoginSource {
             ListField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Manga (Jp)", "jp"), ListValue("Manhwa (Kr)", "kr"), ListValue("Manhua (Cn)", "cn"), ListValue("Artbook", "ar"), ListValue("Other", "ot"))),
             ListField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Manga (Jp)", "jp"), ListValue("Manhwa (Kr)", "kr"), ListValue("Manhua (Cn)", "cn"), ListValue("Artbook", "ar"), ListValue("Other", "ot"))),
             Status(),
             Status(),
             Flag("Exclude mature", "mature", "m", ""),
             Flag("Exclude mature", "mature", "m", ""),
-            Filter.Header(""),
             ListField("Order by", "order_cond", arrayOf(ListValue("Title", "title"), ListValue("Author", "author"), ListValue("Artist", "artist"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Last Update", "update")), 4),
             ListField("Order by", "order_cond", arrayOf(ListValue("Title", "title"), ListValue("Author", "author"), ListValue("Artist", "artist"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Last Update", "update")), 4),
             Flag("Ascending order", "order", "asc", "desc"),
             Flag("Ascending order", "order", "asc", "desc"),
             Filter.Header("Genres"),
             Filter.Header("Genres"),

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt

@@ -155,7 +155,6 @@ class Mangafox(override val id: Int) : ParsedOnlineSource() {
             TextField("Artist", "artist"),
             TextField("Artist", "artist"),
             ListField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Japanese Manga", "1"), ListValue("Korean Manhwa", "2"), ListValue("Chinese Manhua", "3"))),
             ListField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Japanese Manga", "1"), ListValue("Korean Manhwa", "2"), ListValue("Chinese Manhua", "3"))),
             Genre("Completed", "is_completed"),
             Genre("Completed", "is_completed"),
-            Filter.Header(""),
             ListField("Order by", "sort", arrayOf(ListValue("Series name", "name"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Total chapters", "total_chapters"), ListValue("Last chapter", "last_chapter_time")), 2),
             ListField("Order by", "sort", arrayOf(ListValue("Series name", "name"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Total chapters", "total_chapters"), ListValue("Last chapter", "last_chapter_time")), 2),
             Order(),
             Order(),
             Filter.Header("Genres"),
             Filter.Header("Genres"),

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt

@@ -162,7 +162,6 @@ class Mangahere(override val id: Int) : ParsedOnlineSource() {
             TextField("Artist", "artist"),
             TextField("Artist", "artist"),
             ListField("Type", "direction", arrayOf(ListValue("Any", ""), ListValue("Japanese Manga (read from right to left)", "rl"), ListValue("Korean Manhwa (read from left to right)", "lr"))),
             ListField("Type", "direction", arrayOf(ListValue("Any", ""), ListValue("Japanese Manga (read from right to left)", "rl"), ListValue("Korean Manhwa (read from left to right)", "lr"))),
             Status(),
             Status(),
-            Filter.Header(""),
             ListField("Order by", "sort", arrayOf(ListValue("Series name", "name"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Total chapters", "total_chapters"), ListValue("Last chapter", "last_chapter_time")), 2),
             ListField("Order by", "sort", arrayOf(ListValue("Series name", "name"), ListValue("Rating", "rating"), ListValue("Views", "views"), ListValue("Total chapters", "total_chapters"), ListValue("Last chapter", "last_chapter_time")), 2),
             Order(),
             Order(),
             Filter.Header("Genres"),
             Filter.Header("Genres"),

+ 59 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt

@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.catalogue
 import android.content.res.Configuration
 import android.content.res.Configuration
 import android.os.Bundle
 import android.os.Bundle
 import android.support.design.widget.Snackbar
 import android.support.design.widget.Snackbar
+import android.support.v4.widget.DrawerLayout
 import android.support.v7.widget.*
 import android.support.v7.widget.*
 import android.view.*
 import android.view.*
 import android.view.animation.AnimationUtils
 import android.view.animation.AnimationUtils
@@ -18,10 +19,12 @@ import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
 import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.manga.MangaActivity
 import eu.kanade.tachiyomi.ui.manga.MangaActivity
+import eu.kanade.tachiyomi.util.inflate
 import eu.kanade.tachiyomi.util.snack
 import eu.kanade.tachiyomi.util.snack
 import eu.kanade.tachiyomi.util.toast
 import eu.kanade.tachiyomi.util.toast
 import eu.kanade.tachiyomi.widget.EndlessScrollListener
 import eu.kanade.tachiyomi.widget.EndlessScrollListener
 import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
 import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
+import kotlinx.android.synthetic.main.activity_main.*
 import kotlinx.android.synthetic.main.fragment_catalogue.*
 import kotlinx.android.synthetic.main.fragment_catalogue.*
 import kotlinx.android.synthetic.main.toolbar.*
 import kotlinx.android.synthetic.main.toolbar.*
 import nucleus.factory.RequiresPresenter
 import nucleus.factory.RequiresPresenter
@@ -100,6 +103,30 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
     private val toolbar: Toolbar
     private val toolbar: Toolbar
         get() = (activity as MainActivity).toolbar
         get() = (activity as MainActivity).toolbar
 
 
+    /**
+     * Navigation view containing filter items.
+     */
+    private var navView: CatalogueNavigationView? = null
+
+    /**
+     * Drawer listener to allow swipe only for closing the drawer.
+     */
+    private val drawerListener by lazy {
+        object : DrawerLayout.SimpleDrawerListener() {
+            override fun onDrawerClosed(drawerView: View) {
+                if (drawerView == navView) {
+                    activity.drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, navView)
+                }
+            }
+
+            override fun onDrawerOpened(drawerView: View) {
+                if (drawerView == navView) {
+                    activity.drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, navView)
+                }
+            }
+        }
+    }
+
     companion object {
     companion object {
         /**
         /**
          * Creates a new instance of this fragment.
          * Creates a new instance of this fragment.
@@ -176,6 +203,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
                 glm.scrollToPositionWithOffset(0, 0)
                 glm.scrollToPositionWithOffset(0, 0)
                 llm.scrollToPositionWithOffset(0, 0)
                 llm.scrollToPositionWithOffset(0, 0)
                 presenter.setActiveSource(source)
                 presenter.setActiveSource(source)
+                navView?.setFilters(presenter.sourceFilters)
                 activity.invalidateOptionsMenu()
                 activity.invalidateOptionsMenu()
             }
             }
         }
         }
@@ -191,6 +219,32 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
         setToolbarTitle("")
         setToolbarTitle("")
         toolbar.addView(spinner)
         toolbar.addView(spinner)
 
 
+        // Inflate and prepare drawer
+        val navView = activity.drawer.inflate(R.layout.catalogue_drawer) as CatalogueNavigationView
+        this.navView = navView
+        activity.drawer.addView(navView)
+        activity.drawer.addDrawerListener(drawerListener)
+        navView.setFilters(presenter.sourceFilters)
+
+        navView.post {
+            if (isAdded && !activity.drawer.isDrawerOpen(navView))
+                activity.drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, navView)
+        }
+
+        navView.onSearchClicked = {
+            val allDefault = (0..navView.adapter.items.lastIndex)
+                    .none { navView.adapter.items[it].state != presenter.source.filters[it].state }
+
+            presenter.setSourceFilter(if (allDefault) emptyList() else navView.adapter.items)
+        }
+
+        navView.onResetClicked = {
+            presenter.appliedFilters = emptyList()
+            val newFilters = presenter.source.getFilterList()
+            presenter.sourceFilters = newFilters
+            navView.setFilters(newFilters)
+        }
+
         showProgressBar()
         showProgressBar()
     }
     }
 
 
@@ -244,7 +298,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         when (item.itemId) {
         when (item.itemId) {
             R.id.action_display_mode -> swapDisplayMode()
             R.id.action_display_mode -> swapDisplayMode()
-            R.id.action_set_filter -> showFiltersDialog()
+            R.id.action_set_filter -> navView?.let { activity.drawer.openDrawer(Gravity.END) }
             else -> return super.onOptionsItemSelected(item)
             else -> return super.onOptionsItemSelected(item)
         }
         }
         return true
         return true
@@ -263,6 +317,10 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
     }
     }
 
 
     override fun onDestroyView() {
     override fun onDestroyView() {
+        navView?.let {
+            activity.drawer.removeDrawerListener(drawerListener)
+            activity.drawer.removeView(it)
+        }
         numColumnsSubscription?.unsubscribe()
         numColumnsSubscription?.unsubscribe()
         searchItem?.let {
         searchItem?.let {
             if (it.isActionViewExpanded) it.collapseActionView()
             if (it.isActionViewExpanded) it.collapseActionView()
@@ -448,29 +506,4 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
                 }.show()
                 }.show()
     }
     }
 
 
-    /**
-     * Show the filter dialog for the source.
-     */
-    private fun showFiltersDialog() {
-        val adapter = FilterAdapter(if (presenter.filters.isEmpty()) presenter.source.getFilterList() // make a copy
-        else presenter.filters)
-        MaterialDialog.Builder(context)
-                .title(R.string.action_set_filter)
-                .adapter(adapter, null)
-                .onPositive() { dialog, which ->
-                    showProgressBar()
-                    var allDefault = true
-                    for (i in 0..adapter.filters.lastIndex) {
-                        if (adapter.filters[i].state != presenter.source.filters[i].state) {
-                            allDefault = false
-                            break
-                        }
-                    }
-                    presenter.setSourceFilter(if (allDefault) emptyList() else adapter.filters)
-                }
-                .positiveText(android.R.string.ok)
-                .negativeText(android.R.string.cancel)
-                .show()
-    }
-
 }
 }

+ 151 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt

@@ -0,0 +1,151 @@
+package eu.kanade.tachiyomi.ui.catalogue
+
+import android.content.Context
+import android.support.graphics.drawable.VectorDrawableCompat
+import android.support.v7.widget.RecyclerView
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.TextView
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.source.online.OnlineSource.Filter
+import eu.kanade.tachiyomi.util.dpToPx
+import eu.kanade.tachiyomi.util.getResourceColor
+import eu.kanade.tachiyomi.util.inflate
+import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
+import eu.kanade.tachiyomi.widget.SimpleNavigationView
+import eu.kanade.tachiyomi.widget.SimpleTextWatcher
+import kotlinx.android.synthetic.main.catalogue_drawer_content.view.*
+
+
+class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
+    : SimpleNavigationView(context, attrs) {
+
+    val adapter = Adapter()
+
+    var onSearchClicked = {}
+
+    var onResetClicked = {}
+
+    init {
+        recycler.adapter = adapter
+        val view = inflate(R.layout.catalogue_drawer_content)
+        (view as ViewGroup).addView(recycler)
+        addView(view)
+
+        search_btn.setOnClickListener { onSearchClicked() }
+        reset_btn.setOnClickListener { onResetClicked() }
+    }
+
+    fun setFilters(items: List<Filter<*>>) {
+        adapter.items = items
+        adapter.notifyDataSetChanged()
+    }
+
+    inner class Adapter : RecyclerView.Adapter<Holder>() {
+
+        var items: List<Filter<*>> = emptyList()
+
+        override fun getItemCount(): Int {
+            return items.size
+        }
+
+        override fun getItemViewType(position: Int): Int {
+            return when (items[position]) {
+                is Filter.Header -> VIEW_TYPE_HEADER
+                is Filter.CheckBox -> VIEW_TYPE_CHECKBOX
+                is Filter.TriState -> VIEW_TYPE_MULTISTATE
+                is Filter.List<*> -> VIEW_TYPE_LIST
+                is Filter.Text -> VIEW_TYPE_TEXT
+            }
+        }
+
+        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
+            return when (viewType) {
+                VIEW_TYPE_HEADER -> HeaderHolder(parent)
+                VIEW_TYPE_CHECKBOX -> CheckboxHolder(parent, null)
+                VIEW_TYPE_MULTISTATE -> MultiStateHolder(parent, null).apply {
+                    // Adjust view with checkbox
+                    text.setPadding(4.dpToPx, 0, 0, 0)
+                    text.compoundDrawablePadding = 20.dpToPx
+                }
+                VIEW_TYPE_LIST -> SpinnerHolder(parent)
+                VIEW_TYPE_TEXT -> EditTextHolder(parent)
+                else -> throw Exception("Unknown view type")
+            }
+        }
+
+        override fun onBindViewHolder(holder: Holder, position: Int) {
+            val filter = items[position]
+            when (filter) {
+                is Filter.Header -> {
+                    val view = holder.itemView as TextView
+                    view.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
+                    view.text = filter.name
+                }
+                is Filter.CheckBox -> {
+                    val view = (holder as CheckboxHolder).check
+                    view.text = filter.name
+                    view.isChecked = filter.state
+                    holder.itemView.setOnClickListener {
+                        view.toggle()
+                        filter.state = view.isChecked
+                    }
+                }
+                is Filter.TriState -> {
+                    val view = (holder as MultiStateHolder).text
+                    view.text = filter.name
+
+                    fun getIcon() = VectorDrawableCompat.create(view.resources, when (filter.state) {
+                        Filter.TriState.STATE_IGNORE -> R.drawable.ic_check_box_outline_blank_24dp
+                        Filter.TriState.STATE_INCLUDE -> R.drawable.ic_check_box_24dp
+                        Filter.TriState.STATE_EXCLUDE -> R.drawable.ic_check_box_x_24dp
+                        else -> throw Exception("Unknown state")
+                    }, null)?.apply {
+                        val color = if (filter.state == Filter.TriState.STATE_INCLUDE)
+                            R.attr.colorAccent
+                        else
+                            android.R.attr.textColorSecondary
+
+                        setTint(view.context.theme.getResourceColor(color))
+                    }
+
+                    view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
+                    holder.itemView.setOnClickListener {
+                        filter.state = (filter.state + 1) % 3
+                        view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
+                    }
+                }
+                is Filter.List<*> -> {
+                    holder as SpinnerHolder
+                    holder.text.text = filter.name + ": "
+
+                    val spinner = holder.spinner
+                    spinner.prompt = filter.name
+                    spinner.adapter = ArrayAdapter<Any>(holder.itemView.context,
+                            android.R.layout.simple_spinner_item, filter.values).apply {
+                        setDropDownViewResource(R.layout.spinner_item)
+                    }
+                    spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
+                        filter.state = position
+                    }
+                    spinner.setSelection(filter.state)
+                }
+                is Filter.Text -> {
+                    holder as EditTextHolder
+                    holder.wrapper.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
+                    holder.wrapper.hint = filter.name
+                    holder.edit.setText(filter.state)
+                    holder.edit.addTextChangedListener(object : SimpleTextWatcher() {
+                        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+                            filter.state = s.toString()
+                        }
+                    })
+                }
+            }
+        }
+
+    }
+
+}

+ 11 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt

@@ -65,9 +65,14 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
         private set
         private set
 
 
     /**
     /**
-     * Filters states.
+     * Modifiable list of filters.
      */
      */
-    var filters: List<Filter<*>> = emptyList()
+    var sourceFilters: List<Filter<*>> = emptyList()
+
+    /**
+     * List of filters used by the [Pager]. If empty alongside [query], the popular query is used.
+     */
+    var appliedFilters: List<Filter<*>> = emptyList()
 
 
     /**
     /**
      * Pager containing a list of manga results.
      * Pager containing a list of manga results.
@@ -105,6 +110,7 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
 
 
         try {
         try {
             source = getLastUsedSource()
             source = getLastUsedSource()
+            sourceFilters = source.getFilterList()
         } catch (error: NoSuchElementException) {
         } catch (error: NoSuchElementException) {
             return
             return
         }
         }
@@ -130,9 +136,9 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
      * @param query the query.
      * @param query the query.
      * @param filters the current state of the filters (for search mode).
      * @param filters the current state of the filters (for search mode).
      */
      */
-    fun restartPager(query: String = this.query, filters: List<Filter<*>> = this.filters) {
+    fun restartPager(query: String = this.query, filters: List<Filter<*>> = this.appliedFilters) {
         this.query = query
         this.query = query
-        this.filters = filters
+        this.appliedFilters = filters
 
 
         if (!isListMode) {
         if (!isListMode) {
             subscribeToMangaInitializer()
             subscribeToMangaInitializer()
@@ -182,6 +188,7 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
     fun setActiveSource(source: OnlineSource) {
     fun setActiveSource(source: OnlineSource) {
         prefs.lastUsedCatalogueSource().set(source.id)
         prefs.lastUsedCatalogueSource().set(source.id)
         this.source = source
         this.source = source
+        sourceFilters = source.getFilterList()
 
 
         restartPager(query = "", filters = emptyList())
         restartPager(query = "", filters = emptyList())
     }
     }

+ 0 - 153
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/FilterAdapter.kt

@@ -1,153 +0,0 @@
-package eu.kanade.tachiyomi.ui.catalogue
-
-import android.content.Context
-import android.graphics.Typeface
-import android.support.graphics.drawable.VectorDrawableCompat
-import android.support.v7.widget.RecyclerView
-import android.view.View
-import android.view.ViewGroup
-import android.widget.*
-import android.widget.AdapterView.OnItemSelectedListener
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.source.online.OnlineSource.Filter
-import android.text.TextWatcher
-import android.text.Editable
-import android.view.inputmethod.EditorInfo
-import android.widget.TextView
-import eu.kanade.tachiyomi.util.inflate
-
-
-class FilterAdapter(val filters: List<Filter<*>>) : RecyclerView.Adapter<FilterAdapter.ViewHolder>() {
-    private companion object {
-        const val HEADER = 0
-        const val CHECKBOX = 1
-        const val TRISTATE = 2
-        const val LIST = 3
-        const val TEXT = 4
-    }
-
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterAdapter.ViewHolder {
-        return when (viewType) {
-            HEADER -> ViewHolder(SepText(parent))
-            LIST -> ViewHolder(TextSpinner(parent.context))
-            TEXT -> ViewHolder(TextEditText(parent.context))
-            else -> ViewHolder(CheckBox(parent.context))
-        }
-    }
-
-    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        val filter = filters[position]
-        when (filter) {
-            is Filter.Header -> {
-                if (filter.name.isEmpty()) (holder.view as SepText).textView.visibility = View.GONE
-                else (holder.view as SepText).textView.text = filter.name
-            }
-            is Filter.CheckBox -> {
-                var checkBox = holder.view as CheckBox
-                checkBox.text = filter.name
-                checkBox.isChecked = filter.state
-                checkBox.setButtonDrawable(VectorDrawableCompat.create(checkBox.getResources(), R.drawable.ic_check_box_set, null))
-                checkBox.setOnCheckedChangeListener { buttonView, isChecked ->
-                    filter.state = isChecked
-                }
-            }
-            is Filter.TriState -> {
-                var triCheckBox = holder.view as CheckBox
-                triCheckBox.text = filter.name
-                val icons = arrayOf(VectorDrawableCompat.create(triCheckBox.getResources(), R.drawable.ic_check_box_outline_blank_24dp, null),
-                        VectorDrawableCompat.create(triCheckBox.getResources(), R.drawable.ic_check_box_24dp, null),
-                        VectorDrawableCompat.create(triCheckBox.getResources(), R.drawable.ic_check_box_x_24dp, null))
-                triCheckBox.setButtonDrawable(icons[filter.state])
-                triCheckBox.invalidate()
-                triCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
-                    filter.state = (filter.state + 1) % 3
-                    triCheckBox.setButtonDrawable(icons[filter.state])
-                    triCheckBox.invalidate()
-                }
-            }
-            is Filter.List<*> -> {
-                var txtSpin = holder.view as TextSpinner
-                if (filter.name.isEmpty()) txtSpin.textView.visibility = View.GONE
-                else txtSpin.textView.text = filter.name + ":"
-                txtSpin.spinner.adapter = ArrayAdapter<Any>(holder.view.context,
-                        android.R.layout.simple_spinner_item, filter.values)
-                txtSpin.spinner.setSelection(filter.state)
-                txtSpin.spinner.onItemSelectedListener = object : OnItemSelectedListener {
-                    override fun onItemSelected(parentView: AdapterView<*>, selectedItemView: View, pos: Int, id: Long) {
-                        filter.state = pos
-                    }
-
-                    override fun onNothingSelected(parentView: AdapterView<*>) {
-                    }
-                }
-            }
-            is Filter.Text -> {
-                var txtEdTx = holder.view as TextEditText
-                if (filter.name.isEmpty()) txtEdTx.textView.visibility = View.GONE
-                else txtEdTx.textView.text = filter.name + ":"
-                txtEdTx.editText.setText(filter.state)
-                txtEdTx.editText.addTextChangedListener(object : TextWatcher {
-                    override fun afterTextChanged(s: Editable) {
-                    }
-
-                    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-                    }
-
-                    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-                        filter.state = s.toString()
-                    }
-                })
-            }
-        }
-    }
-
-    override fun getItemCount(): Int {
-        return filters.size
-    }
-
-    override fun getItemViewType(position: Int): Int {
-        return when (filters[position]) {
-            is Filter.Header -> HEADER
-            is Filter.CheckBox -> CHECKBOX
-            is Filter.TriState -> TRISTATE
-            is Filter.List<*> -> LIST
-            is Filter.Text -> TEXT
-        }
-    }
-
-    class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
-
-    private class SepText(parent: ViewGroup) : LinearLayout(parent.context) {
-        val separator: View = parent.inflate(R.layout.design_navigation_item_separator)
-        val textView: TextView = TextView(context)
-
-        init {
-            orientation = LinearLayout.VERTICAL
-            textView.setTypeface(null, Typeface.BOLD);
-            addView(separator)
-            addView(textView)
-        }
-    }
-
-    private class TextSpinner(context: Context?) : LinearLayout(context) {
-        val textView: TextView = TextView(context)
-        val spinner: Spinner = Spinner(context)
-
-        init {
-            addView(textView)
-            addView(spinner)
-        }
-    }
-
-    private class TextEditText(context: Context?) : LinearLayout(context) {
-        val textView: TextView = TextView(context)
-        val editText: EditText = EditText(context)
-
-        init {
-            addView(textView)
-            editText.setSingleLine()
-            editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
-            addView(editText)
-        }
-    }
-}

+ 1 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt

@@ -39,6 +39,7 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
 
 
     init {
     init {
         recycler.adapter = adapter
         recycler.adapter = adapter
+        addView(recycler)
 
 
         groups.forEach { it.initModels() }
         groups.forEach { it.initModels() }
     }
     }

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt

@@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.ui.reader.ReaderChapter
 import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader
 import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader
 import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader
 import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader
 import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader
 import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader
-import eu.kanade.tachiyomi.util.toast
 import rx.subscriptions.CompositeSubscription
 import rx.subscriptions.CompositeSubscription
 
 
 /**
 /**

+ 9 - 0
app/src/main/java/eu/kanade/tachiyomi/util/DimensionExtensions.kt

@@ -0,0 +1,9 @@
+package eu.kanade.tachiyomi.util
+
+import android.content.res.Resources
+
+val Int.pxToDp: Int
+    get() = (this / Resources.getSystem().displayMetrics.density).toInt()
+
+val Int.dpToPx: Int
+    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

+ 6 - 128
app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt

@@ -1,88 +1,27 @@
 package eu.kanade.tachiyomi.widget
 package eu.kanade.tachiyomi.widget
 
 
-import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Drawable
 import android.support.annotation.CallSuper
 import android.support.annotation.CallSuper
-import android.support.design.R
-import android.support.design.internal.ScrimInsetsFrameLayout
 import android.support.graphics.drawable.VectorDrawableCompat
 import android.support.graphics.drawable.VectorDrawableCompat
 import android.support.v4.content.ContextCompat
 import android.support.v4.content.ContextCompat
-import android.support.v4.view.ViewCompat
-import android.support.v7.widget.LinearLayoutManager
 import android.support.v7.widget.RecyclerView
 import android.support.v7.widget.RecyclerView
-import android.support.v7.widget.TintTypedArray
 import android.util.AttributeSet
 import android.util.AttributeSet
 import android.view.View
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup
-import android.widget.CheckBox
-import android.widget.CheckedTextView
-import android.widget.RadioButton
 import android.widget.TextView
 import android.widget.TextView
+import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.util.getResourceColor
 import eu.kanade.tachiyomi.util.getResourceColor
-import eu.kanade.tachiyomi.util.inflate
-import eu.kanade.tachiyomi.R as TR
 
 
 /**
 /**
  * An alternative implementation of [android.support.design.widget.NavigationView], without menu
  * An alternative implementation of [android.support.design.widget.NavigationView], without menu
  * inflation and allowing customizable items (multiple selections, custom views, etc).
  * inflation and allowing customizable items (multiple selections, custom views, etc).
  */
  */
-@Suppress("LeakingThis")
-@SuppressLint("PrivateResource")
 open class ExtendedNavigationView @JvmOverloads constructor(
 open class ExtendedNavigationView @JvmOverloads constructor(
         context: Context,
         context: Context,
         attrs: AttributeSet? = null,
         attrs: AttributeSet? = null,
         defStyleAttr: Int = 0)
         defStyleAttr: Int = 0)
-: ScrimInsetsFrameLayout(context, attrs, defStyleAttr) {
-
-    /**
-     * Max width of the navigation view.
-     */
-    private var maxWidth: Int
-
-    /**
-     * Recycler view containing all the items.
-     */
-    protected val recycler = RecyclerView(context)
-
-    init {
-        // Custom attributes
-        val a = TintTypedArray.obtainStyledAttributes(context, attrs,
-                R.styleable.NavigationView, defStyleAttr,
-                R.style.Widget_Design_NavigationView)
-
-        ViewCompat.setBackground(
-                this, a.getDrawable(R.styleable.NavigationView_android_background))
-
-        if (a.hasValue(R.styleable.NavigationView_elevation)) {
-            ViewCompat.setElevation(this, a.getDimensionPixelSize(
-                    R.styleable.NavigationView_elevation, 0).toFloat())
-        }
-
-        ViewCompat.setFitsSystemWindows(this,
-                a.getBoolean(R.styleable.NavigationView_android_fitsSystemWindows, false))
-
-        maxWidth = a.getDimensionPixelSize(R.styleable.NavigationView_android_maxWidth, 0)
-
-        a.recycle()
-
-        recycler.layoutManager = LinearLayoutManager(context)
-        addView(recycler)
-    }
-
-    /**
-     * Overriden to measure the width of the navigation view.
-     */
-    override fun onMeasure(widthSpec: Int, heightSpec: Int) {
-        val width = when (MeasureSpec.getMode(widthSpec)) {
-            MeasureSpec.AT_MOST -> MeasureSpec.makeMeasureSpec(
-                    Math.min(MeasureSpec.getSize(widthSpec), maxWidth), MeasureSpec.EXACTLY)
-            MeasureSpec.UNSPECIFIED -> MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY)
-            else -> widthSpec
-        }
-        // Let super sort out the height
-        super.onMeasure(width, heightSpec)
-    }
+: SimpleNavigationView(context, attrs, defStyleAttr) {
 
 
     /**
     /**
      * Every item of the nav view. Generic items must belong to this list, custom items could be
      * Every item of the nav view. Generic items must belong to this list, custom items could be
@@ -136,7 +75,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
              */
              */
             fun tintVector(context: Context, resId: Int): Drawable {
             fun tintVector(context: Context, resId: Int): Drawable {
                 return VectorDrawableCompat.create(context.resources, resId, context.theme)!!.apply {
                 return VectorDrawableCompat.create(context.resources, resId, context.theme)!!.apply {
-                    setTint(context.theme.getResourceColor(TR.attr.colorAccent))
+                    setTint(context.theme.getResourceColor(R.attr.colorAccent))
                 }
                 }
             }
             }
         }
         }
@@ -161,9 +100,9 @@ open class ExtendedNavigationView @JvmOverloads constructor(
 
 
             override fun getStateDrawable(context: Context): Drawable? {
             override fun getStateDrawable(context: Context): Drawable? {
                 return when (state) {
                 return when (state) {
-                    SORT_ASC -> tintVector(context, TR.drawable.ic_keyboard_arrow_up_black_32dp)
-                    SORT_DESC -> tintVector(context, TR.drawable.ic_keyboard_arrow_down_black_32dp)
-                    SORT_NONE -> ContextCompat.getDrawable(context, TR.drawable.empty_drawable_32dp)
+                    SORT_ASC -> tintVector(context, R.drawable.ic_keyboard_arrow_up_black_32dp)
+                    SORT_DESC -> tintVector(context, R.drawable.ic_keyboard_arrow_down_black_32dp)
+                    SORT_NONE -> ContextCompat.getDrawable(context, R.drawable.empty_drawable_32dp)
                     else -> null
                     else -> null
                 }
                 }
             }
             }
@@ -218,59 +157,6 @@ open class ExtendedNavigationView @JvmOverloads constructor(
 
 
     }
     }
 
 
-    /**
-     * Base view holder.
-     */
-    abstract class Holder(view: View) : RecyclerView.ViewHolder(view)
-
-    /**
-     * Separator view holder.
-     */
-    class SeparatorHolder(parent: ViewGroup)
-        : Holder(parent.inflate(R.layout.design_navigation_item_separator))
-
-    /**
-     * Header view holder.
-     */
-    class HeaderHolder(parent: ViewGroup)
-        : Holder(parent.inflate(R.layout.design_navigation_item_subheader))
-
-    /**
-     * Clickable view holder.
-     */
-    abstract class ClickableHolder(view: View, listener: View.OnClickListener?) : Holder(view) {
-        init {
-            itemView.setOnClickListener(listener)
-        }
-    }
-
-    /**
-     * Radio view holder.
-     */
-    class RadioHolder(parent: ViewGroup, listener: View.OnClickListener?)
-        : ClickableHolder(parent.inflate(TR.layout.navigation_view_radio), listener) {
-
-        val radio = itemView.findViewById(TR.id.nav_view_item) as RadioButton
-    }
-
-    /**
-     * Checkbox view holder.
-     */
-    class CheckboxHolder(parent: ViewGroup, listener: View.OnClickListener?)
-        : ClickableHolder(parent.inflate(TR.layout.navigation_view_checkbox), listener) {
-
-        val check = itemView.findViewById(TR.id.nav_view_item) as CheckBox
-    }
-
-    /**
-     * Multi state view holder.
-     */
-    class MultiStateHolder(parent: ViewGroup, listener: View.OnClickListener?)
-        : ClickableHolder(parent.inflate(TR.layout.navigation_view_checkedtext), listener) {
-
-        val text = itemView.findViewById(TR.id.nav_view_item) as CheckedTextView
-    }
-
     /**
     /**
      * Base adapter for the navigation view. It knows how to create and render every subclass of
      * Base adapter for the navigation view. It knows how to create and render every subclass of
      * [Item].
      * [Item].
@@ -352,12 +238,4 @@ open class ExtendedNavigationView @JvmOverloads constructor(
 
 
     }
     }
 
 
-    companion object {
-        private const val VIEW_TYPE_HEADER = 100
-        private const val VIEW_TYPE_SEPARATOR = 101
-        private const val VIEW_TYPE_RADIO = 102
-        private const val VIEW_TYPE_CHECKBOX = 103
-        private const val VIEW_TYPE_MULTISTATE = 104
-    }
-
 }
 }

+ 152 - 0
app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt

@@ -0,0 +1,152 @@
+package eu.kanade.tachiyomi.widget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.support.design.R
+import android.support.design.internal.ScrimInsetsFrameLayout
+import android.support.design.widget.TextInputLayout
+import android.support.v4.view.ViewCompat
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.TintTypedArray
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import eu.kanade.tachiyomi.util.inflate
+import eu.kanade.tachiyomi.R as TR
+
+@Suppress("LeakingThis")
+@SuppressLint("PrivateResource")
+open class SimpleNavigationView @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyleAttr: Int = 0)
+: ScrimInsetsFrameLayout(context, attrs, defStyleAttr) {
+
+    /**
+     * Max width of the navigation view.
+     */
+    private var maxWidth: Int
+
+    /**
+     * Recycler view containing all the items.
+     */
+    protected val recycler = RecyclerView(context)
+
+    init {
+        // Custom attributes
+        val a = TintTypedArray.obtainStyledAttributes(context, attrs,
+                R.styleable.NavigationView, defStyleAttr,
+                R.style.Widget_Design_NavigationView)
+
+        ViewCompat.setBackground(
+                this, a.getDrawable(R.styleable.NavigationView_android_background))
+
+        if (a.hasValue(R.styleable.NavigationView_elevation)) {
+            ViewCompat.setElevation(this, a.getDimensionPixelSize(
+                    R.styleable.NavigationView_elevation, 0).toFloat())
+        }
+
+        ViewCompat.setFitsSystemWindows(this,
+                a.getBoolean(R.styleable.NavigationView_android_fitsSystemWindows, false))
+
+        maxWidth = a.getDimensionPixelSize(R.styleable.NavigationView_android_maxWidth, 0)
+
+        a.recycle()
+
+        recycler.layoutManager = LinearLayoutManager(context)
+    }
+
+    /**
+     * Overriden to measure the width of the navigation view.
+     */
+    override fun onMeasure(widthSpec: Int, heightSpec: Int) {
+        val width = when (MeasureSpec.getMode(widthSpec)) {
+            MeasureSpec.AT_MOST -> MeasureSpec.makeMeasureSpec(
+                    Math.min(MeasureSpec.getSize(widthSpec), maxWidth), MeasureSpec.EXACTLY)
+            MeasureSpec.UNSPECIFIED -> MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY)
+            else -> widthSpec
+        }
+        // Let super sort out the height
+        super.onMeasure(width, heightSpec)
+    }
+
+    /**
+     * Base view holder.
+     */
+    abstract class Holder(view: View) : RecyclerView.ViewHolder(view)
+
+    /**
+     * Separator view holder.
+     */
+    class SeparatorHolder(parent: ViewGroup)
+        : Holder(parent.inflate(R.layout.design_navigation_item_separator))
+
+    /**
+     * Header view holder.
+     */
+    class HeaderHolder(parent: ViewGroup)
+        : Holder(parent.inflate(R.layout.design_navigation_item_subheader))
+
+    /**
+     * Clickable view holder.
+     */
+    abstract class ClickableHolder(view: View, listener: View.OnClickListener?) : Holder(view) {
+        init {
+            itemView.setOnClickListener(listener)
+        }
+    }
+
+    /**
+     * Radio view holder.
+     */
+    class RadioHolder(parent: ViewGroup, listener: View.OnClickListener?)
+        : ClickableHolder(parent.inflate(TR.layout.navigation_view_radio), listener) {
+
+        val radio = itemView.findViewById(TR.id.nav_view_item) as RadioButton
+    }
+
+    /**
+     * Checkbox view holder.
+     */
+    class CheckboxHolder(parent: ViewGroup, listener: View.OnClickListener?)
+        : ClickableHolder(parent.inflate(TR.layout.navigation_view_checkbox), listener) {
+
+        val check = itemView.findViewById(TR.id.nav_view_item) as CheckBox
+    }
+
+    /**
+     * Multi state view holder.
+     */
+    class MultiStateHolder(parent: ViewGroup, listener: View.OnClickListener?)
+        : ClickableHolder(parent.inflate(TR.layout.navigation_view_checkedtext), listener) {
+
+        val text = itemView.findViewById(TR.id.nav_view_item) as CheckedTextView
+    }
+
+    class SpinnerHolder(parent: ViewGroup, listener: OnClickListener? = null)
+        : ClickableHolder(parent.inflate(TR.layout.navigation_view_spinner), listener) {
+
+        val text = itemView.findViewById(TR.id.nav_view_item_text) as TextView
+        val spinner = itemView.findViewById(TR.id.nav_view_item) as Spinner
+    }
+
+    class EditTextHolder(parent: ViewGroup)
+        : Holder(parent.inflate(TR.layout.navigation_view_text)) {
+
+        val wrapper  = itemView.findViewById(TR.id.nav_view_item_wrapper) as TextInputLayout
+        val edit = itemView.findViewById(TR.id.nav_view_item) as EditText
+    }
+
+    protected companion object {
+        const val VIEW_TYPE_HEADER = 100
+        const val VIEW_TYPE_SEPARATOR = 101
+        const val VIEW_TYPE_RADIO = 102
+        const val VIEW_TYPE_CHECKBOX = 103
+        const val VIEW_TYPE_MULTISTATE = 104
+        const val VIEW_TYPE_TEXT = 105
+        const val VIEW_TYPE_LIST = 106
+    }
+
+}

+ 0 - 5
app/src/main/res/drawable/ic_check_box_set.xml

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true" android:drawable="@drawable/ic_check_box_24dp" />
-    <item android:drawable="@drawable/ic_check_box_outline_blank_24dp" />
-</selector>

+ 9 - 0
app/src/main/res/layout/catalogue_drawer.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<eu.kanade.tachiyomi.ui.catalogue.CatalogueNavigationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/nav_view2"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:layout_gravity="end"
+    android:fitsSystemWindows="false"/>
+

+ 28 - 0
app/src/main/res/layout/catalogue_drawer_content.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="8dp">
+
+        <Button
+            android:id="@+id/search_btn"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/action_search"/>
+
+        <Button
+            android:id="@+id/reset_btn"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/action_reset"/>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 25 - 0
app/src/main/res/layout/navigation_view_spinner.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/listPreferredItemHeightSmall"
+    android:paddingLeft="?attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?attr/listPreferredItemPaddingRight"
+    android:background="?attr/selectableItemBackground"
+    android:focusable="true">
+
+    <TextView
+        android:id="@+id/nav_view_item_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <Spinner
+        android:id="@+id/nav_view_item"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical|start"
+        android:maxLines="1"
+        android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
+
+</LinearLayout>

+ 29 - 0
app/src/main/res/layout/navigation_view_text.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/listPreferredItemHeightSmall"
+    android:paddingLeft="?attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?attr/listPreferredItemPaddingRight"
+    android:background="?attr/selectableItemBackground"
+    android:focusable="true">
+
+    <android.support.design.widget.TextInputLayout
+        android:id="@+id/nav_view_item_wrapper"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical|start">
+
+        <EditText
+            android:id="@+id/nav_view_item"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
+
+    </android.support.design.widget.TextInputLayout>
+
+
+
+</LinearLayout>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -69,6 +69,7 @@
     <string name="action_install">Install</string>
     <string name="action_install">Install</string>
     <string name="action_share">Share</string>
     <string name="action_share">Share</string>
     <string name="action_save">Save</string>
     <string name="action_save">Save</string>
+    <string name="action_reset">Reset</string>
 
 
     <!-- Operations -->
     <!-- Operations -->
     <string name="deleting">Deleting…</string>
     <string name="deleting">Deleting…</string>