home: refactor list management

Return to the "four seperate list fragments" system when it comes to
HomeFragment. This reduces code complexity [no more massive when
chains] and allows me to customize the content of each fragment without
adding special cases.
This commit is contained in:
OxygenCobalt 2021-10-01 19:48:23 -06:00
parent 394327a2c4
commit e946648b24
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
11 changed files with 406 additions and 370 deletions

View file

@ -36,6 +36,10 @@ import org.oxycblt.auxio.MainFragmentDirections
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeBinding import org.oxycblt.auxio.databinding.FragmentHomeBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.home.list.AlbumListFragment
import org.oxycblt.auxio.home.list.ArtistListFragment
import org.oxycblt.auxio.home.list.GenreListFragment
import org.oxycblt.auxio.home.list.SongListFragment
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
@ -242,6 +246,14 @@ class HomeFragment : Fragment() {
FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) { FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) {
override fun getItemCount(): Int = homeModel.tabs.value!!.size override fun getItemCount(): Int = homeModel.tabs.value!!.size
override fun createFragment(position: Int): Fragment = HomeListFragment.new(position)
override fun createFragment(position: Int): Fragment {
return when (homeModel.tabs.value!![position]) {
DisplayMode.SHOW_SONGS -> SongListFragment()
DisplayMode.SHOW_ALBUMS -> AlbumListFragment()
DisplayMode.SHOW_ARTISTS -> ArtistListFragment()
DisplayMode.SHOW_GENRES -> GenreListFragment()
}
}
} }
} }

View file

@ -1,151 +0,0 @@
/*
* Copyright (c) 2021 Auxio Project
* HomeListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.recycler.HomeAdapter
import org.oxycblt.auxio.home.recycler.ParentAdapter
import org.oxycblt.auxio.home.recycler.SongsAdapter
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Parent
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.newMenu
import org.oxycblt.auxio.util.applySpans
import org.oxycblt.auxio.util.logD
/**
* Fragment that contains a list of items specified by a [DisplayMode]. This fragment
* should be created using the [new] method with it's position in the ViewPager.
*/
class HomeListFragment : Fragment() {
private val homeModel: HomeViewModel by activityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentHomeListBinding.inflate(inflater)
// Get some tab-specific values before we go ahead. More specifically, the data to use
// and the unique ID that HomeFragment's AppBarLayout uses to determine lift state.
val pos = requireNotNull(arguments).getInt(ARG_POS)
@IdRes val customId: Int
val homeAdapter: HomeAdapter<out BaseModel>
val homeData: LiveData<out List<BaseModel>>
when (homeModel.tabs.value!![pos]) {
DisplayMode.SHOW_SONGS -> {
customId = R.id.home_song_list
homeData = homeModel.songs
homeAdapter = SongsAdapter(::onSongClick, ::newMenu, playbackModel)
}
DisplayMode.SHOW_ALBUMS -> {
customId = R.id.home_album_list
homeData = homeModel.albums
homeAdapter = ParentAdapter(::onParentClick, ::newMenu)
}
DisplayMode.SHOW_ARTISTS -> {
customId = R.id.home_artist_list
homeData = homeModel.artists
homeAdapter = ParentAdapter(::onParentClick, ::newMenu)
}
DisplayMode.SHOW_GENRES -> {
customId = R.id.home_genre_list
homeData = homeModel.genres
homeAdapter = ParentAdapter(::onParentClick, ::newMenu)
}
}
// --- UI SETUP ---
binding.lifecycleOwner = viewLifecycleOwner
binding.homeRecycler.apply {
id = customId
adapter = homeAdapter
setHasFixedSize(true)
applySpans()
}
// --- VIEWMODEL SETUP ---
// Make sure that this RecyclerView has data before startup
homeData.observe(viewLifecycleOwner) { data ->
homeAdapter.updateData(data)
}
logD("Fragment created")
return binding.root
}
private fun onSongClick(song: Song) {
playbackModel.playSong(song)
}
private fun onParentClick(parent: Parent) {
when (parent) {
is Album -> findNavController().navigate(
HomeFragmentDirections.actionShowAlbum(parent.id)
)
is Artist -> findNavController().navigate(
HomeFragmentDirections.actionShowArtist(parent.id)
)
is Genre -> findNavController().navigate(
HomeFragmentDirections.actionShowGenre(parent.id)
)
}
}
companion object {
private const val ARG_POS = BuildConfig.APPLICATION_ID + ".key.POS"
/*
* Instantiates this fragment for use in a ViewPager.
*/
fun new(pos: Int): HomeListFragment {
val fragment = HomeListFragment()
fragment.arguments = Bundle().apply {
putInt(ARG_POS, pos)
}
return fragment
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Auxio Project
* AlbumListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.list
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.HomeFragmentDirections
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.ui.AlbumViewHolder
import org.oxycblt.auxio.ui.newMenu
class AlbumListFragment : HomeListFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding.lifecycleOwner = viewLifecycleOwner
val adapter = AlbumAdapter(
doOnClick = { album ->
findNavController().navigate(
HomeFragmentDirections.actionShowAlbum(album.id)
)
},
::newMenu
)
setupRecycler(R.id.home_album_list, adapter, homeModel.albums)
return binding.root
}
class AlbumAdapter(
private val doOnClick: (data: Album) -> Unit,
private val doOnLongClick: (view: View, data: Album) -> Unit,
) : HomeAdapter<Album, AlbumViewHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AlbumViewHolder {
return AlbumViewHolder.from(parent.context, doOnClick, doOnLongClick)
}
override fun onBindViewHolder(holder: AlbumViewHolder, position: Int) {
holder.bind(data[position])
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Auxio Project
* AlbumListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.list
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.HomeFragmentDirections
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.ui.ArtistViewHolder
import org.oxycblt.auxio.ui.newMenu
class ArtistListFragment : HomeListFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding.lifecycleOwner = viewLifecycleOwner
val adapter = ArtistAdapter(
doOnClick = { artist ->
findNavController().navigate(
HomeFragmentDirections.actionShowArtist(artist.id)
)
},
::newMenu
)
setupRecycler(R.id.home_artist_list, adapter, homeModel.artists)
return binding.root
}
class ArtistAdapter(
private val doOnClick: (data: Artist) -> Unit,
private val doOnLongClick: (view: View, data: Artist) -> Unit,
) : HomeAdapter<Artist, ArtistViewHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistViewHolder {
return ArtistViewHolder.from(parent.context, doOnClick, doOnLongClick)
}
override fun onBindViewHolder(holder: ArtistViewHolder, position: Int) {
holder.bind(data[position])
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Auxio Project
* AlbumListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.list
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.HomeFragmentDirections
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.ui.GenreViewHolder
import org.oxycblt.auxio.ui.newMenu
class GenreListFragment : HomeListFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding.lifecycleOwner = viewLifecycleOwner
val adapter = GenreAdapter(
doOnClick = { Genre ->
findNavController().navigate(
HomeFragmentDirections.actionShowGenre(Genre.id)
)
},
::newMenu
)
setupRecycler(R.id.home_genre_list, adapter, homeModel.genres)
return binding.root
}
class GenreAdapter(
private val doOnClick: (data: Genre) -> Unit,
private val doOnLongClick: (view: View, data: Genre) -> Unit,
) : HomeAdapter<Genre, GenreViewHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenreViewHolder {
return GenreViewHolder.from(parent.context, doOnClick, doOnLongClick)
}
override fun onBindViewHolder(holder: GenreViewHolder, position: Int) {
holder.bind(data[position])
}
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2021 Auxio Project
* HomeListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.list
import android.annotation.SuppressLint
import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.memberBinding
import org.oxycblt.auxio.util.applySpans
open class HomeListFragment : Fragment() {
protected val binding: FragmentHomeListBinding by memberBinding(
FragmentHomeListBinding::inflate
)
protected val homeModel: HomeViewModel by activityViewModels()
protected val playbackModel: PlaybackViewModel by activityViewModels()
protected fun <T : BaseModel, VH : RecyclerView.ViewHolder> setupRecycler(
@IdRes uniqueId: Int,
homeAdapter: HomeAdapter<T, VH>,
homeData: LiveData<List<T>>,
) {
binding.homeRecycler.apply {
id = uniqueId
adapter = homeAdapter
setHasFixedSize(true)
applySpans()
}
// Make sure that this RecyclerView has data before startup
homeData.observe(viewLifecycleOwner) { data ->
homeAdapter.updateData(data)
}
}
abstract class HomeAdapter<T : BaseModel, VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {
protected var data = listOf<T>()
@SuppressLint("NotifyDataSetChanged")
fun updateData(newData: List<T>) {
data = newData
notifyDataSetChanged()
}
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2021 Auxio Project
* SongListFragment.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.list
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ItemPlayShuffleBinding
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.SongViewHolder
import org.oxycblt.auxio.ui.newMenu
import org.oxycblt.auxio.util.inflater
class SongListFragment : HomeListFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding.lifecycleOwner = viewLifecycleOwner
val adapter = SongsAdapter(
doOnClick = { song ->
playbackModel.playSong(song)
},
::newMenu
)
setupRecycler(R.id.home_song_list, adapter, homeModel.songs)
return binding.root
}
inner class SongsAdapter(
private val doOnClick: (data: Song) -> Unit,
private val doOnLongClick: (view: View, data: Song) -> Unit,
) : HomeAdapter<Song, RecyclerView.ViewHolder>() {
override fun getItemCount(): Int {
return if (data.isNotEmpty()) {
data.size + 1 // Make space for the play/shuffle header
} else {
data.size
}
}
override fun getItemViewType(position: Int): Int {
return if (position == 0) {
PLAY_ITEM_TYPE
} else {
SongViewHolder.ITEM_TYPE
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
PLAY_ITEM_TYPE -> PlayViewHolder(
ItemPlayShuffleBinding.inflate(parent.context.inflater)
)
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
else -> error("Invalid viewholder item type.")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is SongViewHolder) {
holder.bind(data[position - 1])
}
}
}
private inner class PlayViewHolder(
binding: ItemPlayShuffleBinding
) : RecyclerView.ViewHolder(binding.root) {
init {
// Force the layout to *actually* be the screen width.
// We can't inherit BaseViewHolder here since this ViewHolder isn't really connected
// to an item.
binding.root.layoutParams = RecyclerView.LayoutParams(
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
binding.playButton.setOnClickListener {
playbackModel.playAll()
}
binding.shuffleButton.setOnClickListener {
playbackModel.shuffleAll()
}
}
}
companion object {
const val PLAY_ITEM_TYPE = 0xA00E
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (c) 2021 Auxio Project
* HomeAdapter.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.recycler
import android.annotation.SuppressLint
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.music.BaseModel
/**
* A base class that implements an [updateData] that is required across [SongsAdapter] and [ParentAdapter]
*/
abstract class HomeAdapter<T : BaseModel> : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
protected var data = listOf<BaseModel>()
/**
* Update the data with [newData]. [notifyDataSetChanged] will be called.
*/
@SuppressLint("NotifyDataSetChanged")
fun updateData(newData: List<BaseModel>) {
data = newData
// I would use ListAdapter instead of this inefficient invalidate call, but they still
// haven't fixed the issue where ListAdapter's calculations will cause wild scrolling
// for basically no reason.
notifyDataSetChanged()
}
}

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2021 Auxio Project
* ParentAdapter.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.recycler
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Parent
import org.oxycblt.auxio.ui.AlbumViewHolder
import org.oxycblt.auxio.ui.ArtistViewHolder
import org.oxycblt.auxio.ui.GenreViewHolder
/**
* A universal adapter for displaying [Parent] data.
*/
class ParentAdapter(
private val doOnClick: (data: Parent) -> Unit,
private val doOnLongClick: (view: View, data: Parent) -> Unit,
) : HomeAdapter<Parent>() {
override fun getItemCount(): Int = data.size
override fun getItemViewType(position: Int): Int {
return when (data[position]) {
is Genre -> GenreViewHolder.ITEM_TYPE
is Artist -> ArtistViewHolder.ITEM_TYPE
is Album -> AlbumViewHolder.ITEM_TYPE
else -> error("Unsupported item ${data[position]::class.simpleName}")
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
else -> error("Invalid viewholder item type.")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = data[position]) {
is Genre -> (holder as GenreViewHolder).bind(item)
is Artist -> (holder as ArtistViewHolder).bind(item)
is Album -> (holder as AlbumViewHolder).bind(item)
}
}
}

View file

@ -1,98 +0,0 @@
/*
* Copyright (c) 2021 Auxio Project
* HomeAdapter.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.recycler
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemPlayShuffleBinding
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.SongViewHolder
import org.oxycblt.auxio.util.inflater
/**
* An adapter for displaying a song list with a special play/shuffle header.
* Note that the data for the play/pause icon does not need to be included with the data
* you are submitting. It is automatically handled by the adapter.
* TODO: Maybe extend play/shuffle to all items?
*/
class SongsAdapter(
private val doOnClick: (data: Song) -> Unit,
private val doOnLongClick: (view: View, data: Song) -> Unit,
private val playbackModel: PlaybackViewModel
) : HomeAdapter<Song>() {
override fun getItemCount(): Int = if
(data.isEmpty()) 0 // Account for the play/shuffle viewholder
else
data.size + 1
override fun getItemViewType(position: Int): Int {
return if (position == 0) {
PLAY_ITEM_TYPE
} else {
SongViewHolder.ITEM_TYPE
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
PLAY_ITEM_TYPE -> PlayViewHolder(
ItemPlayShuffleBinding.inflate(parent.context.inflater)
)
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
else -> error("Invalid viewholder item type.")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is SongViewHolder) {
holder.bind(data[position - 1] as Song)
}
}
private inner class PlayViewHolder(
binding: ItemPlayShuffleBinding
) : RecyclerView.ViewHolder(binding.root) {
init {
// Force the layout to *actually* be the screen width.
// We can't inherit BaseViewHolder here since this ViewHolder isn't really connected
// to an item.
binding.root.layoutParams = RecyclerView.LayoutParams(
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
binding.playButton.setOnClickListener {
playbackModel.playAll()
}
binding.shuffleButton.setOnClickListener {
playbackModel.shuffleAll()
}
}
}
companion object {
const val PLAY_ITEM_TYPE = 0xA00E
}
}

View file

@ -305,7 +305,7 @@ class MusicLoader(private val context: Context) {
// Songs that don't have a genre will be thrown into an unknown genre. // Songs that don't have a genre will be thrown into an unknown genre.
val unknownGenre = Genre( val unknownGenre = Genre(
id = -2, id = Long.MIN_VALUE,
name = context.getString(R.string.def_genre) name = context.getString(R.string.def_genre)
) )
@ -315,7 +315,7 @@ class MusicLoader(private val context: Context) {
} }
} }
if (unknownGenre.songs.isEmpty()) { if (unknownGenre.songs.isNotEmpty()) {
genres.add(unknownGenre) genres.add(unknownGenre)
} }
} }