recycler: add span size abstraction to adapter
Make adapter instances handle span sizes. This supercedes the hackier solution where the fragments would have to reference adapter data in order to determine span size. Not anymore.
This commit is contained in:
parent
acaf679000
commit
be8623ad2d
11 changed files with 50 additions and 43 deletions
|
|
@ -41,7 +41,6 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
|||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.Sort
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.canScroll
|
||||
import org.oxycblt.auxio.util.collect
|
||||
|
|
@ -84,13 +83,7 @@ class AlbumDetailFragment :
|
|||
setOnMenuItemClickListener(this@AlbumDetailFragment)
|
||||
}
|
||||
|
||||
binding.detailRecycler.apply {
|
||||
adapter = detailAdapter
|
||||
setSpanSizeLookup { pos ->
|
||||
val item = detailAdapter.currentList[pos]
|
||||
item is Album || item is Header || item is SortHeader
|
||||
}
|
||||
}
|
||||
binding.detailRecycler.adapter = detailAdapter
|
||||
|
||||
// -- VIEWMODEL SETUP ---
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
|||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.Sort
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
|
|
@ -79,13 +78,7 @@ class ArtistDetailFragment :
|
|||
setOnMenuItemClickListener(this@ArtistDetailFragment)
|
||||
}
|
||||
|
||||
binding.detailRecycler.apply {
|
||||
adapter = detailAdapter
|
||||
setSpanSizeLookup { pos ->
|
||||
val item = detailAdapter.currentList[pos]
|
||||
item is Artist || item is Header || item is SortHeader
|
||||
}
|
||||
}
|
||||
binding.detailRecycler.adapter = detailAdapter
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
|||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.Sort
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
|
|
@ -80,13 +79,7 @@ class GenreDetailFragment :
|
|||
setOnMenuItemClickListener(this@GenreDetailFragment)
|
||||
}
|
||||
|
||||
binding.detailRecycler.apply {
|
||||
adapter = detailAdapter
|
||||
setSpanSizeLookup { pos ->
|
||||
val item = detailAdapter.currentList[pos]
|
||||
item is Genre || item is Header || item is SortHeader
|
||||
}
|
||||
}
|
||||
binding.detailRecycler.adapter = detailAdapter
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ class AlbumDetailAdapter(private val listener: Listener) :
|
|||
}
|
||||
}
|
||||
|
||||
override fun isItemFullWidth(position: Int): Boolean {
|
||||
val item = differ.currentList[position]
|
||||
return super.isItemFullWidth(position) || item is Album || item is DiscHeader
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFFER =
|
||||
object : SimpleItemCallback<Item>() {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,11 @@ class ArtistDetailAdapter(private val listener: Listener) :
|
|||
}
|
||||
}
|
||||
|
||||
override fun isItemFullWidth(position: Int): Boolean {
|
||||
val item = differ.currentList[position]
|
||||
return super.isItemFullWidth(position) || item is Artist
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFFER =
|
||||
object : SimpleItemCallback<Item>() {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.databinding.ItemSortHeaderBinding
|
||||
import org.oxycblt.auxio.detail.SortHeader
|
||||
import org.oxycblt.auxio.ui.recycler.AuxioRecyclerView
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.HeaderViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.IndicatorAdapter
|
||||
|
|
@ -38,7 +39,7 @@ import org.oxycblt.auxio.util.inflater
|
|||
abstract class DetailAdapter<L : DetailAdapter.Listener>(
|
||||
private val listener: L,
|
||||
diffCallback: DiffUtil.ItemCallback<Item>
|
||||
) : IndicatorAdapter<RecyclerView.ViewHolder>() {
|
||||
) : IndicatorAdapter<RecyclerView.ViewHolder>(), AuxioRecyclerView.SpanSizeLookup {
|
||||
private var isPlaying = false
|
||||
|
||||
@Suppress("LeakingThis") override fun getItemCount() = differ.currentList.size
|
||||
|
|
@ -77,6 +78,11 @@ abstract class DetailAdapter<L : DetailAdapter.Listener>(
|
|||
super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
override fun isItemFullWidth(position: Int): Boolean {
|
||||
val item = differ.currentList[position]
|
||||
return item is Header || item is SortHeader
|
||||
}
|
||||
|
||||
protected val differ = AsyncListDiffer(this, diffCallback)
|
||||
|
||||
override val currentList: List<Item>
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ class GenreDetailAdapter(private val listener: Listener) :
|
|||
}
|
||||
}
|
||||
|
||||
override fun isItemFullWidth(position: Int): Boolean {
|
||||
val item = differ.currentList[position]
|
||||
return super.isItemFullWidth(position) || item is Genre
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DIFFER =
|
||||
object : SimpleItemCallback<Item>() {
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ import org.oxycblt.auxio.util.getColorCompat
|
|||
import org.oxycblt.auxio.util.getDrawableCompat
|
||||
|
||||
/**
|
||||
* View that displays the playback indicator. Nominally emulates [StyledImageView], but is
|
||||
* much different internally as an animated icon can't be wrapped within StyledDrawable without
|
||||
* causing insane issues.
|
||||
* View that displays the playback indicator. Nominally emulates [StyledImageView], but is much
|
||||
* different internally as an animated icon can't be wrapped within StyledDrawable without causing
|
||||
* insane issues.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class IndicatorView
|
||||
|
|
@ -45,7 +45,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
private val playingIndicatorDrawable =
|
||||
context.getDrawableCompat(R.drawable.ic_playing_indicator_24) as AnimationDrawable
|
||||
|
||||
private val pausedIndicatorDrawable = context.getDrawableCompat(R.drawable.ic_paused_indicator_24)
|
||||
private val pausedIndicatorDrawable =
|
||||
context.getDrawableCompat(R.drawable.ic_paused_indicator_24)
|
||||
|
||||
private val indicatorMatrix = Matrix()
|
||||
private val indicatorMatrixSrc = RectF()
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.oxycblt.auxio.music.Genre
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.ui.recycler.AlbumViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.ArtistViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.AuxioRecyclerView
|
||||
import org.oxycblt.auxio.ui.recycler.GenreViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.HeaderViewHolder
|
||||
|
|
@ -36,7 +37,7 @@ import org.oxycblt.auxio.ui.recycler.SimpleItemCallback
|
|||
import org.oxycblt.auxio.ui.recycler.SongViewHolder
|
||||
|
||||
class SearchAdapter(private val listener: MenuItemListener) :
|
||||
IndicatorAdapter<RecyclerView.ViewHolder>() {
|
||||
IndicatorAdapter<RecyclerView.ViewHolder>(), AuxioRecyclerView.SpanSizeLookup {
|
||||
private val differ = AsyncListDiffer(this, DIFFER)
|
||||
|
||||
override fun getItemCount() = differ.currentList.size
|
||||
|
|
@ -79,6 +80,8 @@ class SearchAdapter(private val listener: MenuItemListener) :
|
|||
}
|
||||
}
|
||||
|
||||
override fun isItemFullWidth(position: Int) = differ.currentList[position] is Header
|
||||
|
||||
override val currentList: List<Item>
|
||||
get() = differ.currentList
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import org.oxycblt.auxio.music.MusicParent
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
||||
import org.oxycblt.auxio.util.androidViewModels
|
||||
|
|
@ -104,10 +103,7 @@ class SearchFragment :
|
|||
}
|
||||
}
|
||||
|
||||
binding.searchRecycler.apply {
|
||||
adapter = searchAdapter
|
||||
setSpanSizeLookup { pos -> searchAdapter.currentList[pos] is Header }
|
||||
}
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
|
|
|
|||
|
|
@ -54,13 +54,20 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
return insets
|
||||
}
|
||||
|
||||
// TODO: Move abstraction to adapters since using external data will not work well
|
||||
inline fun setSpanSizeLookup(crossinline fullWidth: (Int) -> Boolean) {
|
||||
val glm = layoutManager as GridLayoutManager
|
||||
val spanCount = glm.spanCount
|
||||
override fun setAdapter(adapter: Adapter<*>?) {
|
||||
super.setAdapter(adapter)
|
||||
|
||||
if (adapter is SpanSizeLookup) {
|
||||
val glm = (layoutManager as GridLayoutManager)
|
||||
glm.spanSizeLookup =
|
||||
object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int) = if (fullWidth(position)) spanCount else 1
|
||||
override fun getSpanSize(position: Int) =
|
||||
if (adapter.isItemFullWidth(position)) glm.spanCount else 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface SpanSizeLookup {
|
||||
fun isItemFullWidth(position: Int): Boolean
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue