Change filters dialog with a drawer
This commit is contained in:
parent
d3e9200a7f
commit
c25af3d5ad
18 changed files with 481 additions and 320 deletions
|
@ -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"),
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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()
|
|
@ -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) {
|
: SimpleNavigationView(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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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_ASC -> tintVector(context, R.drawable.ic_keyboard_arrow_up_black_32dp)
|
||||||
SORT_DESC -> tintVector(context, TR.drawable.ic_keyboard_arrow_down_black_32dp)
|
SORT_DESC -> tintVector(context, R.drawable.ic_keyboard_arrow_down_black_32dp)
|
||||||
SORT_NONE -> ContextCompat.getDrawable(context, TR.drawable.empty_drawable_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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
app/src/main/res/layout/catalogue_drawer.xml
Normal file
9
app/src/main/res/layout/catalogue_drawer.xml
Normal file
|
@ -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
app/src/main/res/layout/catalogue_drawer_content.xml
Normal file
28
app/src/main/res/layout/catalogue_drawer_content.xml
Normal file
|
@ -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
app/src/main/res/layout/navigation_view_spinner.xml
Normal file
25
app/src/main/res/layout/navigation_view_spinner.xml
Normal file
|
@ -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
app/src/main/res/layout/navigation_view_text.xml
Normal file
29
app/src/main/res/layout/navigation_view_text.xml
Normal file
|
@ -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>
|
|
@ -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>
|
||||||
|
|
Reference in a new issue