Replace ClickListener with lambdas
Replace ClickListener with direct lambdas, so that adapters with multiple datatypes dont have to duplicate ClickListener for each type.
This commit is contained in:
parent
a72ab10007
commit
d8f40bfd27
24 changed files with 106 additions and 147 deletions
|
@ -15,7 +15,6 @@ import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import org.oxycblt.auxio.databinding.FragmentMainBinding
|
import org.oxycblt.auxio.databinding.FragmentMainBinding
|
||||||
import org.oxycblt.auxio.library.LibraryFragment
|
import org.oxycblt.auxio.library.LibraryFragment
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
|
||||||
import org.oxycblt.auxio.songs.SongsFragment
|
import org.oxycblt.auxio.songs.SongsFragment
|
||||||
import org.oxycblt.auxio.theme.accent
|
import org.oxycblt.auxio.theme.accent
|
||||||
import org.oxycblt.auxio.theme.getInactiveAlpha
|
import org.oxycblt.auxio.theme.getInactiveAlpha
|
||||||
|
@ -27,8 +26,6 @@ class MainFragment : Fragment() {
|
||||||
MusicViewModel.Factory(requireActivity().application)
|
MusicViewModel.Factory(requireActivity().application)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private val shownFragments = listOf(0, 1)
|
private val shownFragments = listOf(0, 1)
|
||||||
private val tabIcons = listOf(
|
private val tabIcons = listOf(
|
||||||
R.drawable.ic_library,
|
R.drawable.ic_library,
|
||||||
|
@ -91,8 +88,6 @@ class MainFragment : Fragment() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- VIEWMODEL SETUP ---
|
|
||||||
|
|
||||||
Log.d(this::class.simpleName, "Fragment Created.")
|
Log.d(this::class.simpleName, "Fragment Created.")
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
|
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.theme.applyDivider
|
import org.oxycblt.auxio.theme.applyDivider
|
||||||
import org.oxycblt.auxio.theme.disable
|
import org.oxycblt.auxio.theme.disable
|
||||||
|
|
||||||
|
@ -45,11 +44,9 @@ class AlbumDetailFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val songAdapter = DetailSongAdapter(
|
val songAdapter = DetailSongAdapter {
|
||||||
ClickListener {
|
|
||||||
playbackModel.updateSong(it)
|
playbackModel.updateSong(it)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
|
import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.theme.applyDivider
|
import org.oxycblt.auxio.theme.applyDivider
|
||||||
import org.oxycblt.auxio.theme.disable
|
import org.oxycblt.auxio.theme.disable
|
||||||
|
|
||||||
|
@ -45,8 +44,7 @@ class ArtistDetailFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val albumAdapter = DetailAlbumAdapter(
|
val albumAdapter = DetailAlbumAdapter {
|
||||||
ClickListener {
|
|
||||||
if (!detailModel.isNavigating) {
|
if (!detailModel.isNavigating) {
|
||||||
detailModel.updateNavigationStatus(true)
|
detailModel.updateNavigationStatus(true)
|
||||||
|
|
||||||
|
@ -55,7 +53,6 @@ class ArtistDetailFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import org.oxycblt.auxio.recycler.SortMode
|
||||||
// TODO:
|
// TODO:
|
||||||
// - Implement a system where the Toolbar will update with the info [And Media Controls] when
|
// - Implement a system where the Toolbar will update with the info [And Media Controls] when
|
||||||
// the main info of the detail fragment is removed.
|
// the main info of the detail fragment is removed.
|
||||||
// - Implement shared element transitions [If that is even possible]
|
|
||||||
class DetailViewModel : ViewModel() {
|
class DetailViewModel : ViewModel() {
|
||||||
private var mIsNavigating = false
|
private var mIsNavigating = false
|
||||||
val isNavigating: Boolean get() = mIsNavigating
|
val isNavigating: Boolean get() = mIsNavigating
|
||||||
|
@ -39,24 +38,8 @@ class DetailViewModel : ViewModel() {
|
||||||
private val mNavToParent = MutableLiveData<Boolean>()
|
private val mNavToParent = MutableLiveData<Boolean>()
|
||||||
val navToParent: LiveData<Boolean> get() = mNavToParent
|
val navToParent: LiveData<Boolean> get() = mNavToParent
|
||||||
|
|
||||||
fun updateGenre(genre: Genre) {
|
fun updateNavigationStatus(value: Boolean) {
|
||||||
mCurrentGenre.value = genre
|
mIsNavigating = value
|
||||||
}
|
|
||||||
|
|
||||||
fun updateArtist(artist: Artist) {
|
|
||||||
mCurrentArtist.value = artist
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateAlbum(album: Album) {
|
|
||||||
mCurrentAlbum.value = album
|
|
||||||
}
|
|
||||||
|
|
||||||
fun doNavToParent() {
|
|
||||||
mNavToParent.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun doneWithNavToParent() {
|
|
||||||
mNavToParent.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun incrementGenreSortMode() {
|
fun incrementGenreSortMode() {
|
||||||
|
@ -88,7 +71,23 @@ class DetailViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateNavigationStatus(value: Boolean) {
|
fun updateGenre(genre: Genre) {
|
||||||
mIsNavigating = value
|
mCurrentGenre.value = genre
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateArtist(artist: Artist) {
|
||||||
|
mCurrentArtist.value = artist
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAlbum(album: Album) {
|
||||||
|
mCurrentAlbum.value = album
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doNavToParent() {
|
||||||
|
mNavToParent.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doneWithNavToParent() {
|
||||||
|
mNavToParent.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
|
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.theme.applyDivider
|
import org.oxycblt.auxio.theme.applyDivider
|
||||||
import org.oxycblt.auxio.theme.disable
|
import org.oxycblt.auxio.theme.disable
|
||||||
|
|
||||||
|
@ -42,8 +41,7 @@ class GenreDetailFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val artistAdapter = DetailArtistAdapter(
|
val artistAdapter = DetailArtistAdapter {
|
||||||
ClickListener {
|
|
||||||
if (!detailModel.isNavigating) {
|
if (!detailModel.isNavigating) {
|
||||||
detailModel.updateNavigationStatus(true)
|
detailModel.updateNavigationStatus(true)
|
||||||
|
|
||||||
|
@ -52,7 +50,6 @@ class GenreDetailFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,11 @@ import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
|
|
||||||
class DetailAlbumAdapter(
|
class DetailAlbumAdapter(
|
||||||
private val listener: ClickListener<Album>
|
private val doOnClick: (Album) -> Unit
|
||||||
) : ListAdapter<Album, DetailAlbumAdapter.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<Album, DetailAlbumAdapter.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -26,7 +25,7 @@ class DetailAlbumAdapter(
|
||||||
// Generic ViewHolder for a detail album
|
// Generic ViewHolder for a detail album
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ItemArtistAlbumBinding
|
private val binding: ItemArtistAlbumBinding
|
||||||
) : BaseViewHolder<Album>(binding, listener) {
|
) : BaseViewHolder<Album>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Album) {
|
override fun onBind(model: Album) {
|
||||||
binding.album = model
|
binding.album = model
|
||||||
|
|
|
@ -5,12 +5,11 @@ import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import org.oxycblt.auxio.databinding.ItemGenreArtistBinding
|
import org.oxycblt.auxio.databinding.ItemGenreArtistBinding
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
|
|
||||||
class DetailArtistAdapter(
|
class DetailArtistAdapter(
|
||||||
private val listener: ClickListener<Artist>
|
private val doOnClick: (Artist) -> Unit
|
||||||
) : ListAdapter<Artist, DetailArtistAdapter.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<Artist, DetailArtistAdapter.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -26,7 +25,7 @@ class DetailArtistAdapter(
|
||||||
// Generic ViewHolder for an album
|
// Generic ViewHolder for an album
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ItemGenreArtistBinding
|
private val binding: ItemGenreArtistBinding
|
||||||
) : BaseViewHolder<Artist>(binding, listener) {
|
) : BaseViewHolder<Artist>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Artist) {
|
override fun onBind(model: Artist) {
|
||||||
binding.artist = model
|
binding.artist = model
|
||||||
|
|
|
@ -5,12 +5,11 @@ import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
|
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
|
|
||||||
class DetailSongAdapter(
|
class DetailSongAdapter(
|
||||||
private val listener: ClickListener<Song>
|
private val doOnClick: (Song) -> Unit
|
||||||
) : ListAdapter<Song, DetailSongAdapter.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<Song, DetailSongAdapter.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -26,7 +25,7 @@ class DetailSongAdapter(
|
||||||
// Generic ViewHolder for a song
|
// Generic ViewHolder for a song
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ItemAlbumSongBinding
|
private val binding: ItemAlbumSongBinding
|
||||||
) : BaseViewHolder<Song>(binding, listener) {
|
) : BaseViewHolder<Song>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Song) {
|
override fun onBind(model: Song) {
|
||||||
binding.song = model
|
binding.song = model
|
||||||
|
|
|
@ -86,6 +86,7 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
val searchView = item.actionView as SearchView
|
val searchView = item.actionView as SearchView
|
||||||
|
|
||||||
searchView.queryHint = getString(R.string.hint_search_library)
|
searchView.queryHint = getString(R.string.hint_search_library)
|
||||||
|
searchView.maxWidth = Int.MAX_VALUE
|
||||||
searchView.setOnQueryTextListener(this@LibraryFragment)
|
searchView.setOnQueryTextListener(this@LibraryFragment)
|
||||||
searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||||
libraryModel.updateSearchFocusStatus(hasFocus)
|
libraryModel.updateSearchFocusStatus(hasFocus)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.ShowMode
|
import org.oxycblt.auxio.recycler.ShowMode
|
||||||
import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder
|
||||||
import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
|
||||||
|
@ -20,12 +19,6 @@ class LibraryAdapter(
|
||||||
private val doOnClick: (BaseModel) -> Unit
|
private val doOnClick: (BaseModel) -> Unit
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
// Create separate listeners for each type, as ClickListeners can be converted
|
|
||||||
// to a type-specific form.
|
|
||||||
private val genreListener = ClickListener<Genre> { doOnClick(it) }
|
|
||||||
private val artistListener = ClickListener<Artist> { doOnClick(it) }
|
|
||||||
private val albumListener = ClickListener<Album> { doOnClick(it) }
|
|
||||||
|
|
||||||
private var data: List<BaseModel>
|
private var data: List<BaseModel>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -44,10 +37,10 @@ class LibraryAdapter(
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
// Return a different View Holder depending on the show type
|
// Return a different View Holder depending on the show type
|
||||||
return when (showMode) {
|
return when (showMode) {
|
||||||
ShowMode.SHOW_GENRES -> GenreViewHolder.from(parent.context, genreListener)
|
ShowMode.SHOW_GENRES -> GenreViewHolder.from(parent.context, doOnClick)
|
||||||
ShowMode.SHOW_ARTISTS -> ArtistViewHolder.from(parent.context, artistListener)
|
ShowMode.SHOW_ARTISTS -> ArtistViewHolder.from(parent.context, doOnClick)
|
||||||
ShowMode.SHOW_ALBUMS -> AlbumViewHolder.from(parent.context, albumListener)
|
ShowMode.SHOW_ALBUMS -> AlbumViewHolder.from(parent.context, doOnClick)
|
||||||
else -> ArtistViewHolder.from(parent.context, artistListener)
|
else -> ArtistViewHolder.from(parent.context, doOnClick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder
|
||||||
import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
|
||||||
|
@ -21,14 +20,6 @@ class SearchAdapter(
|
||||||
private val doOnClick: (BaseModel) -> Unit
|
private val doOnClick: (BaseModel) -> Unit
|
||||||
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback<BaseModel>()) {
|
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback<BaseModel>()) {
|
||||||
|
|
||||||
// Create separate listeners for each type, as a BaseModel ClickListener cant be
|
|
||||||
// casted to a ClickListener of a class that inherits BaseModel.
|
|
||||||
// FIXME: Maybe there's a way for this to be improved?
|
|
||||||
private val genreListener = ClickListener<Genre> { doOnClick(it) }
|
|
||||||
private val artistListener = ClickListener<Artist> { doOnClick(it) }
|
|
||||||
private val albumListener = ClickListener<Album> { doOnClick(it) }
|
|
||||||
private val songListener = ClickListener<Song> { doOnClick(it) }
|
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Genre -> GenreViewHolder.ITEM_TYPE
|
is Genre -> GenreViewHolder.ITEM_TYPE
|
||||||
|
@ -41,10 +32,10 @@ class SearchAdapter(
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(parent.context, genreListener)
|
GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(parent.context, doOnClick)
|
||||||
ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(parent.context, artistListener)
|
ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(parent.context, doOnClick)
|
||||||
AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(parent.context, albumListener)
|
AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(parent.context, doOnClick)
|
||||||
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(parent.context, songListener)
|
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(parent.context, doOnClick)
|
||||||
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
|
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
|
||||||
|
|
||||||
else -> HeaderViewHolder.from(parent.context)
|
else -> HeaderViewHolder.from(parent.context)
|
||||||
|
|
|
@ -14,7 +14,6 @@ sealed class BaseModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Song
|
// Song
|
||||||
// TODO: Maybe move durations to a solely-millis system
|
|
||||||
data class Song(
|
data class Song(
|
||||||
override val id: Long = -1,
|
override val id: Long = -1,
|
||||||
override var name: String,
|
override var name: String,
|
||||||
|
|
|
@ -46,6 +46,8 @@ class MosaicFetcher(private val context: Context) : Fetcher<List<Uri>> {
|
||||||
if (streams.size < 4) {
|
if (streams.size < 4) {
|
||||||
streams.forEach { it.close() }
|
streams.forEach { it.close() }
|
||||||
|
|
||||||
|
// FIXME: What if all the streams fail?
|
||||||
|
|
||||||
return SourceResult(
|
return SourceResult(
|
||||||
source = streams[0].source().buffer(),
|
source = streams[0].source().buffer(),
|
||||||
mimeType = context.contentResolver.getType(data[0]),
|
mimeType = context.contentResolver.getType(data[0]),
|
||||||
|
|
|
@ -66,7 +66,7 @@ class MusicLoader(
|
||||||
private fun loadGenres() {
|
private fun loadGenres() {
|
||||||
Log.d(this::class.simpleName, "Starting genre search...")
|
Log.d(this::class.simpleName, "Starting genre search...")
|
||||||
|
|
||||||
// First, get a ui_cursor for every genre in the android system
|
// First, get a cursor for every genre in the android system
|
||||||
genreCursor = resolver.query(
|
genreCursor = resolver.query(
|
||||||
Genres.EXTERNAL_CONTENT_URI,
|
Genres.EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
|
|
@ -35,7 +35,7 @@ class MusicSorter(
|
||||||
|
|
||||||
for (album in albums) {
|
for (album in albums) {
|
||||||
// Find all songs that match the current album ID to prevent any bugs w/comparing names.
|
// Find all songs that match the current album ID to prevent any bugs w/comparing names.
|
||||||
// This cant be done with artists/genres sadly.
|
// This cant be done anywhere else sadly. Blame the genre system.
|
||||||
val albumSongs = songs.filter { it.albumId == album.id }
|
val albumSongs = songs.filter { it.albumId == album.id }
|
||||||
|
|
||||||
// Then add them to the album
|
// Then add them to the album
|
||||||
|
@ -50,7 +50,6 @@ class MusicSorter(
|
||||||
// Any remaining songs will be added to an unknown album
|
// Any remaining songs will be added to an unknown album
|
||||||
if (unknownSongs.size > 0) {
|
if (unknownSongs.size > 0) {
|
||||||
|
|
||||||
// Reuse an existing unknown album if one is found
|
|
||||||
val unknownAlbum = Album(
|
val unknownAlbum = Album(
|
||||||
name = albumPlaceholder,
|
name = albumPlaceholder,
|
||||||
artistName = artistPlaceholder
|
artistName = artistPlaceholder
|
||||||
|
|
|
@ -21,6 +21,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
|
||||||
// TODO: Implement media controls
|
// TODO: Implement media controls
|
||||||
|
// TODO: Make exit icon bigger
|
||||||
// TODO: Implement nav to artists/albums
|
// TODO: Implement nav to artists/albums
|
||||||
// TODO: Possibly implement a trackbar with a spectrum shown as well.
|
// TODO: Possibly implement a trackbar with a spectrum shown as well.
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -53,6 +54,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
// Make marquee scroll work
|
// Make marquee scroll work
|
||||||
binding.playbackSong.isSelected = true
|
binding.playbackSong.isSelected = true
|
||||||
|
|
||||||
binding.playbackSeekBar.setOnSeekBarChangeListener(this)
|
binding.playbackSeekBar.setOnSeekBarChangeListener(this)
|
||||||
|
|
||||||
// --- VIEWMODEL SETUP --
|
// --- VIEWMODEL SETUP --
|
||||||
|
@ -103,8 +105,10 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
// Seeking callbacks
|
// Seeking callbacks
|
||||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||||
|
if (fromUser) {
|
||||||
playbackModel.updateCurrentDurationWithProgress(progress)
|
playbackModel.updateCurrentDurationWithProgress(progress)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||||
playbackModel.setSeekingStatus(true)
|
playbackModel.setSeekingStatus(true)
|
||||||
|
|
|
@ -3,9 +3,6 @@ package org.oxycblt.auxio.recycler
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
|
|
||||||
// RecyclerView click listener
|
|
||||||
class ClickListener<T : BaseModel>(val onClick: (T) -> Unit)
|
|
||||||
|
|
||||||
// Base Diff callback
|
// Base Diff callback
|
||||||
class DiffCallback<T : BaseModel> : DiffUtil.ItemCallback<T>() {
|
class DiffCallback<T : BaseModel> : DiffUtil.ItemCallback<T>() {
|
||||||
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
|
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
|
||||||
|
|
|
@ -3,13 +3,11 @@ package org.oxycblt.auxio.recycler.viewholders
|
||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
|
|
||||||
// ViewHolder abstraction that automates some of the things that are common for all ViewHolders.
|
// ViewHolder abstraction that automates some of the things that are common for all ViewHolders.
|
||||||
// TODO: Implement some kind of abstraction for BaseViewHolder.from()
|
|
||||||
abstract class BaseViewHolder<T : BaseModel>(
|
abstract class BaseViewHolder<T : BaseModel>(
|
||||||
private val baseBinding: ViewDataBinding,
|
private val baseBinding: ViewDataBinding,
|
||||||
protected val listener: ClickListener<T>?
|
private val doOnClick: ((T) -> Unit)?
|
||||||
) : RecyclerView.ViewHolder(baseBinding.root) {
|
) : RecyclerView.ViewHolder(baseBinding.root) {
|
||||||
init {
|
init {
|
||||||
baseBinding.root.layoutParams = RecyclerView.LayoutParams(
|
baseBinding.root.layoutParams = RecyclerView.LayoutParams(
|
||||||
|
@ -18,10 +16,8 @@ abstract class BaseViewHolder<T : BaseModel>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(model: T) {
|
fun bind(model: T) {
|
||||||
if (listener != null) {
|
doOnClick?.let {
|
||||||
baseBinding.root.setOnClickListener {
|
baseBinding.root.setOnClickListener { it(model) }
|
||||||
listener.onClick(model)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBind(model)
|
onBind(model)
|
||||||
|
|
|
@ -12,15 +12,14 @@ import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
|
|
||||||
// Shared ViewHolders for each ViewModel, providing basic information
|
// Shared ViewHolders for each ViewModel, providing basic information
|
||||||
// All new instances should be created with from() instead of direct instantiation.
|
// All new instances should be created with from() instead of direct instantiation.
|
||||||
|
|
||||||
class GenreViewHolder private constructor(
|
class GenreViewHolder private constructor(
|
||||||
listener: ClickListener<Genre>,
|
doOnClick: (Genre) -> Unit,
|
||||||
private val binding: ItemGenreBinding
|
private val binding: ItemGenreBinding
|
||||||
) : BaseViewHolder<Genre>(binding, listener) {
|
) : BaseViewHolder<Genre>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Genre) {
|
override fun onBind(model: Genre) {
|
||||||
binding.genre = model
|
binding.genre = model
|
||||||
|
@ -30,9 +29,9 @@ class GenreViewHolder private constructor(
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 10
|
const val ITEM_TYPE = 10
|
||||||
|
|
||||||
fun from(context: Context, listener: ClickListener<Genre>): GenreViewHolder {
|
fun from(context: Context, doOnClick: (Genre) -> Unit): GenreViewHolder {
|
||||||
return GenreViewHolder(
|
return GenreViewHolder(
|
||||||
ClickListener { listener.onClick(it) },
|
doOnClick,
|
||||||
ItemGenreBinding.inflate(LayoutInflater.from(context))
|
ItemGenreBinding.inflate(LayoutInflater.from(context))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -40,9 +39,9 @@ class GenreViewHolder private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistViewHolder private constructor(
|
class ArtistViewHolder private constructor(
|
||||||
listener: ClickListener<Artist>,
|
doOnClick: (Artist) -> Unit,
|
||||||
private val binding: ItemArtistBinding
|
private val binding: ItemArtistBinding
|
||||||
) : BaseViewHolder<Artist>(binding, listener) {
|
) : BaseViewHolder<Artist>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Artist) {
|
override fun onBind(model: Artist) {
|
||||||
binding.artist = model
|
binding.artist = model
|
||||||
|
@ -52,9 +51,9 @@ class ArtistViewHolder private constructor(
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 11
|
const val ITEM_TYPE = 11
|
||||||
|
|
||||||
fun from(context: Context, listener: ClickListener<Artist>): ArtistViewHolder {
|
fun from(context: Context, doOnClick: (Artist) -> Unit): ArtistViewHolder {
|
||||||
return ArtistViewHolder(
|
return ArtistViewHolder(
|
||||||
ClickListener { listener.onClick(it) },
|
doOnClick,
|
||||||
ItemArtistBinding.inflate(LayoutInflater.from(context))
|
ItemArtistBinding.inflate(LayoutInflater.from(context))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -62,9 +61,9 @@ class ArtistViewHolder private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumViewHolder private constructor(
|
class AlbumViewHolder private constructor(
|
||||||
listener: ClickListener<Album>,
|
doOnClick: (Album) -> Unit,
|
||||||
private val binding: ItemAlbumBinding
|
private val binding: ItemAlbumBinding
|
||||||
) : BaseViewHolder<Album>(binding, listener) {
|
) : BaseViewHolder<Album>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Album) {
|
override fun onBind(model: Album) {
|
||||||
binding.album = model
|
binding.album = model
|
||||||
|
@ -74,9 +73,9 @@ class AlbumViewHolder private constructor(
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 12
|
const val ITEM_TYPE = 12
|
||||||
|
|
||||||
fun from(context: Context, listener: ClickListener<Album>): AlbumViewHolder {
|
fun from(context: Context, doOnClick: (Album) -> Unit): AlbumViewHolder {
|
||||||
return AlbumViewHolder(
|
return AlbumViewHolder(
|
||||||
listener,
|
doOnClick,
|
||||||
ItemAlbumBinding.inflate(LayoutInflater.from(context))
|
ItemAlbumBinding.inflate(LayoutInflater.from(context))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -86,9 +85,9 @@ class AlbumViewHolder private constructor(
|
||||||
// TODO: Add indicators to song recycler items when they're being played.
|
// TODO: Add indicators to song recycler items when they're being played.
|
||||||
|
|
||||||
class SongViewHolder private constructor(
|
class SongViewHolder private constructor(
|
||||||
listener: ClickListener<Song>,
|
doOnClick: (Song) -> Unit,
|
||||||
private val binding: ItemSongBinding
|
private val binding: ItemSongBinding
|
||||||
) : BaseViewHolder<Song>(binding, listener) {
|
) : BaseViewHolder<Song>(binding, doOnClick) {
|
||||||
|
|
||||||
override fun onBind(model: Song) {
|
override fun onBind(model: Song) {
|
||||||
binding.song = model
|
binding.song = model
|
||||||
|
@ -100,9 +99,9 @@ class SongViewHolder private constructor(
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 13
|
const val ITEM_TYPE = 13
|
||||||
|
|
||||||
fun from(context: Context, listener: ClickListener<Song>): SongViewHolder {
|
fun from(context: Context, doOnClick: (Song) -> Unit): SongViewHolder {
|
||||||
return SongViewHolder(
|
return SongViewHolder(
|
||||||
listener,
|
doOnClick,
|
||||||
ItemSongBinding.inflate(LayoutInflater.from(context))
|
ItemSongBinding.inflate(LayoutInflater.from(context))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,17 @@ package org.oxycblt.auxio.songs
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.recycler.viewholders.SongViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.SongViewHolder
|
||||||
|
|
||||||
class SongAdapter(
|
class SongAdapter(
|
||||||
private val data: List<Song>,
|
private val data: List<Song>,
|
||||||
private val listener: ClickListener<Song>
|
private val doOnClick: (Song) -> Unit
|
||||||
) : RecyclerView.Adapter<SongViewHolder>() {
|
) : RecyclerView.Adapter<SongViewHolder>() {
|
||||||
|
|
||||||
override fun getItemCount(): Int = data.size
|
override fun getItemCount(): Int = data.size
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
|
||||||
return SongViewHolder.from(parent.context, listener)
|
return SongViewHolder.from(parent.context, doOnClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import androidx.fragment.app.activityViewModels
|
||||||
import org.oxycblt.auxio.databinding.FragmentSongsBinding
|
import org.oxycblt.auxio.databinding.FragmentSongsBinding
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.ClickListener
|
|
||||||
import org.oxycblt.auxio.theme.applyDivider
|
import org.oxycblt.auxio.theme.applyDivider
|
||||||
|
|
||||||
class SongsFragment : Fragment() {
|
class SongsFragment : Fragment() {
|
||||||
|
@ -33,12 +32,9 @@ class SongsFragment : Fragment() {
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
binding.songRecycler.apply {
|
binding.songRecycler.apply {
|
||||||
adapter = SongAdapter(
|
adapter = SongAdapter(musicModel.songs.value!!) {
|
||||||
musicModel.songs.value!!,
|
playbackModel.updateSong(it)
|
||||||
ClickListener { song ->
|
|
||||||
playbackModel.updateSong(song)
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
applyDivider()
|
applyDivider()
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,25 @@ import org.oxycblt.auxio.R
|
||||||
|
|
||||||
// Pairs of the base accent and its theme
|
// Pairs of the base accent and its theme
|
||||||
private val ACCENTS = listOf(
|
private val ACCENTS = listOf(
|
||||||
Pair(R.color.red, R.style.Theme_Red),
|
Pair(R.color.red, R.style.Theme_Red), // 0
|
||||||
Pair(R.color.pink, R.style.Theme_Pink),
|
Pair(R.color.pink, R.style.Theme_Pink), // 1
|
||||||
Pair(R.color.purple, R.style.Theme_Purple),
|
Pair(R.color.purple, R.style.Theme_Purple), // 2
|
||||||
Pair(R.color.deep_purple, R.style.Theme_DeepPurple),
|
Pair(R.color.deep_purple, R.style.Theme_DeepPurple), // 3
|
||||||
Pair(R.color.indigo, R.style.Theme_Indigo),
|
Pair(R.color.indigo, R.style.Theme_Indigo), // 4
|
||||||
Pair(R.color.blue, R.style.Theme_Blue),
|
Pair(R.color.blue, R.style.Theme_Blue), // 5
|
||||||
Pair(R.color.light_blue, R.style.Theme_Blue),
|
Pair(R.color.light_blue, R.style.Theme_Blue), // 6
|
||||||
Pair(R.color.cyan, R.style.Theme_Cyan),
|
Pair(R.color.cyan, R.style.Theme_Cyan), // 7
|
||||||
Pair(R.color.teal, R.style.Theme_Teal),
|
Pair(R.color.teal, R.style.Theme_Teal), // 8
|
||||||
Pair(R.color.green, R.style.Theme_Green),
|
Pair(R.color.green, R.style.Theme_Green), // 9
|
||||||
Pair(R.color.light_green, R.style.Theme_LightGreen),
|
Pair(R.color.light_green, R.style.Theme_LightGreen), // 10
|
||||||
Pair(R.color.lime, R.style.Theme_Lime),
|
Pair(R.color.lime, R.style.Theme_Lime), // 11
|
||||||
Pair(R.color.yellow, R.style.Theme_Yellow),
|
Pair(R.color.yellow, R.style.Theme_Yellow), // 12
|
||||||
Pair(R.color.amber, R.style.Theme_Amber),
|
Pair(R.color.amber, R.style.Theme_Amber), // 13
|
||||||
Pair(R.color.orange, R.style.Theme_Orange),
|
Pair(R.color.orange, R.style.Theme_Orange), // 14
|
||||||
Pair(R.color.deep_orange, R.style.Theme_DeepOrange),
|
Pair(R.color.deep_orange, R.style.Theme_DeepOrange), // 15
|
||||||
Pair(R.color.brown, R.style.Theme_Brown),
|
Pair(R.color.brown, R.style.Theme_Brown), // 16
|
||||||
Pair(R.color.grey, R.style.Theme_Gray),
|
Pair(R.color.grey, R.style.Theme_Gray), // 17
|
||||||
Pair(R.color.blue_grey, R.style.Theme_BlueGrey)
|
Pair(R.color.blue_grey, R.style.Theme_BlueGrey) // 18
|
||||||
)
|
)
|
||||||
|
|
||||||
val accent = ACCENTS[5]
|
val accent = ACCENTS[5]
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@drawable/ic_play_to_pause"
|
tools:src="@drawable/ic_play_to_pause"
|
||||||
tools:tint="@color/control_color" />
|
android:tint="@color/control_color" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -40,6 +40,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="@dimen/margin_mid_large"
|
android:layout_margin="@dimen/margin_mid_large"
|
||||||
|
android:elevation="4dp"
|
||||||
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
||||||
app:coverArt="@{song}"
|
app:coverArt="@{song}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_song"
|
app:layout_constraintBottom_toTopOf="@+id/playback_song"
|
||||||
|
|
Loading…
Reference in a new issue