diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 581d4820f..0a1746815 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -67,6 +67,8 @@ class AlbumDetailFragment : Fragment() { // If the album was shown directly from LibraryFragment, Then enable the ability to // navigate upwards to the parent artist if (args.enableParentNav) { + detailModel.doneWithNavToParent() + detailModel.navToParent.observe(viewLifecycleOwner) { if (it) { findNavController().navigate( diff --git a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailAlbumAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailAlbumAdapter.kt index dd8a2b1b1..76ebc179b 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailAlbumAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailAlbumAdapter.kt @@ -5,9 +5,9 @@ import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.DiffCallback +import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder class DetailAlbumAdapter( private val listener: ClickListener @@ -23,7 +23,7 @@ class DetailAlbumAdapter( holder.bind(getItem(position)) } - // Generic ViewHolder for an album + // Generic ViewHolder for a detail album inner class ViewHolder( private val binding: ItemArtistAlbumBinding ) : BaseViewHolder(binding, listener) { diff --git a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailArtistAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailArtistAdapter.kt index 42cf088ba..decbb63bf 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailArtistAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailArtistAdapter.kt @@ -5,9 +5,9 @@ import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import org.oxycblt.auxio.databinding.ItemGenreArtistBinding import org.oxycblt.auxio.music.Artist -import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.DiffCallback +import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder class DetailArtistAdapter( private val listener: ClickListener diff --git a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailSongAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailSongAdapter.kt index 025c9a2be..5757a401a 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailSongAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/adapters/DetailSongAdapter.kt @@ -5,9 +5,9 @@ import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import org.oxycblt.auxio.databinding.ItemAlbumSongBinding import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.DiffCallback +import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder class DetailSongAdapter( private val listener: ClickListener diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt index 27dbaace3..0e20d4562 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt @@ -23,7 +23,7 @@ class LibraryViewModel : ViewModel() { val searchHasFocus: Boolean get() = mSearchHasFocus // TODO: Move these to prefs when they're added - private val mShowMode = MutableLiveData(SHOW_ARTISTS) + private val mShowMode = MutableLiveData(SHOW_ALBUMS) val showMode: LiveData get() = mShowMode private val mSortMode = MutableLiveData(SortMode.ALPHA_DOWN) diff --git a/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryAdapter.kt index 8e05dc3d4..c229ab67b 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryAdapter.kt @@ -1,21 +1,21 @@ package org.oxycblt.auxio.library.recycler -import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import org.oxycblt.auxio.databinding.ItemAlbumBinding -import org.oxycblt.auxio.databinding.ItemArtistBinding -import org.oxycblt.auxio.databinding.ItemGenreBinding 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.recycler.ClickListener +import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder +import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder +import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder import org.oxycblt.auxio.theme.SHOW_ALBUMS import org.oxycblt.auxio.theme.SHOW_ARTISTS import org.oxycblt.auxio.theme.SHOW_GENRES -// A Great Value androidx ListAdapter that can display three types of ViewHolders. +// A ListAdapter that can contain three different types of ViewHolders depending +// the showmode given. It cannot display multiple types of viewholders *at once*. class LibraryAdapter( private val showMode: Int, val listener: ClickListener @@ -39,36 +39,21 @@ class LibraryAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { // Return a different View Holder depending on the show type return when (showMode) { - SHOW_GENRES -> GenreViewHolder( - listener, - ItemGenreBinding.inflate(LayoutInflater.from(parent.context)) - ) - - SHOW_ARTISTS -> ArtistViewHolder( - listener, - ItemArtistBinding.inflate(LayoutInflater.from(parent.context)) - ) - - SHOW_ALBUMS -> AlbumViewHolder( - listener, - ItemAlbumBinding.inflate(LayoutInflater.from(parent.context)) - ) - - else -> ArtistViewHolder( - listener, - ItemArtistBinding.inflate(LayoutInflater.from(parent.context)) - ) + SHOW_GENRES -> GenreViewHolder.from(parent.context, listener) + SHOW_ARTISTS -> ArtistViewHolder.from(parent.context, listener) + SHOW_ALBUMS -> AlbumViewHolder.from(parent.context, listener) + else -> ArtistViewHolder.from(parent.context, listener) } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (showMode) { - SHOW_GENRES -> holder as GenreViewHolder - SHOW_ARTISTS -> holder as ArtistViewHolder - SHOW_ALBUMS -> holder as AlbumViewHolder + SHOW_GENRES -> (holder as GenreViewHolder).bind(data[position] as Genre) + SHOW_ARTISTS -> (holder as ArtistViewHolder).bind(data[position] as Artist) + SHOW_ALBUMS -> (holder as AlbumViewHolder).bind(data[position] as Album) else -> return - }.bind(data[position]) + } } // Update the data, as its an internal value. diff --git a/app/src/main/java/org/oxycblt/auxio/library/recycler/SearchAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/recycler/SearchAdapter.kt index 0eafa1ade..cf6dbbe96 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/recycler/SearchAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/recycler/SearchAdapter.kt @@ -1,14 +1,8 @@ package org.oxycblt.auxio.library.recycler -import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import org.oxycblt.auxio.databinding.ItemAlbumBinding -import org.oxycblt.auxio.databinding.ItemArtistBinding -import org.oxycblt.auxio.databinding.ItemGenreBinding -import org.oxycblt.auxio.databinding.ItemHeaderBinding -import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.BaseModel @@ -17,62 +11,34 @@ import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.DiffCallback +import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder +import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder +import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder +import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder +import org.oxycblt.auxio.recycler.viewholders.SongViewHolder class SearchAdapter( private val listener: ClickListener ) : ListAdapter(DiffCallback()) { override fun getItemViewType(position: Int): Int { return when (getItem(position)) { - is Genre -> ITEM_TYPE_GENRE - is Artist -> ITEM_TYPE_ARTIST - is Album -> ITEM_TYPE_ALBUM - is Song -> ITEM_TYPE_SONG - is Header -> ITEM_TYPE_HEADER + is Genre -> GenreViewHolder.ITEM_TYPE + is Artist -> ArtistViewHolder.ITEM_TYPE + is Album -> AlbumViewHolder.ITEM_TYPE + is Song -> SongViewHolder.ITEM_TYPE + is Header -> HeaderViewHolder.ITEM_TYPE } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { - ITEM_TYPE_GENRE -> GenreViewHolder( - listener, - ItemGenreBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) + GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(parent.context, listener) + ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(parent.context, listener) + AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(parent.context, listener) + SongViewHolder.ITEM_TYPE -> SongViewHolder.from(parent.context, listener) + HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context) - ITEM_TYPE_ARTIST -> ArtistViewHolder( - listener, - ItemArtistBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) - - ITEM_TYPE_ALBUM -> AlbumViewHolder( - listener, - ItemAlbumBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) - - ITEM_TYPE_SONG -> SongViewHolder( - listener, - ItemSongBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) - - ITEM_TYPE_HEADER -> HeaderViewHolder( - ItemHeaderBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) - - else -> ArtistViewHolder( - listener, - ItemArtistBinding.inflate( - LayoutInflater.from(parent.context) - ) - ) + else -> HeaderViewHolder.from(parent.context) } } @@ -85,6 +51,6 @@ class SearchAdapter( is HeaderViewHolder -> holder else -> return - }.onBind(getItem(position)) + }.bind(getItem(position)) } } diff --git a/app/src/main/java/org/oxycblt/auxio/library/recycler/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/library/recycler/ViewHolders.kt deleted file mode 100644 index d0391f49f..000000000 --- a/app/src/main/java/org/oxycblt/auxio/library/recycler/ViewHolders.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.oxycblt.auxio.library.recycler - -import org.oxycblt.auxio.databinding.ItemAlbumBinding -import org.oxycblt.auxio.databinding.ItemArtistBinding -import org.oxycblt.auxio.databinding.ItemGenreBinding -import org.oxycblt.auxio.databinding.ItemHeaderBinding -import org.oxycblt.auxio.databinding.ItemSongBinding -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.Header -import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.recycler.BaseViewHolder -import org.oxycblt.auxio.recycler.ClickListener - -const val ITEM_TYPE_GENRE = 10 -const val ITEM_TYPE_ARTIST = 11 -const val ITEM_TYPE_ALBUM = 12 -const val ITEM_TYPE_SONG = 13 -const val ITEM_TYPE_HEADER = 14 - -class GenreViewHolder( - listener: ClickListener, - private val binding: ItemGenreBinding -) : BaseViewHolder(binding, listener) { - - override fun onBind(model: BaseModel) { - binding.genre = model as Genre - binding.genreName.requestLayout() - } -} - -class ArtistViewHolder( - listener: ClickListener, - private val binding: ItemArtistBinding -) : BaseViewHolder(binding, listener) { - - override fun onBind(model: BaseModel) { - binding.artist = model as Artist - binding.artistName.requestLayout() - } -} - -class AlbumViewHolder( - listener: ClickListener, - private val binding: ItemAlbumBinding -) : BaseViewHolder(binding, listener) { - - override fun onBind(model: BaseModel) { - binding.album = model as Album - binding.albumName.requestLayout() - } -} - -class SongViewHolder( - listener: ClickListener, - private val binding: ItemSongBinding -) : BaseViewHolder(binding, listener) { - - override fun onBind(model: BaseModel) { - binding.song = model as Song - - binding.songName.requestLayout() - binding.songInfo.requestLayout() - } -} - -class HeaderViewHolder( - private val binding: ItemHeaderBinding -) : BaseViewHolder(binding, null) { - override fun onBind(model: BaseModel) { - binding.header = model as Header - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt index 316f0204c..a1976918f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -131,7 +131,7 @@ fun TextView.bindArtistCounts(artist: Artist) { // Get a bunch of miscellaneous album information [Year, Songs, Duration] and combine them @BindingAdapter("albumDetails") -fun TextView.bindAlbumDetails(album: Album) { +fun TextView.bindAllAlbumDetails(album: Album) { text = context.getString( R.string.format_double_info, album.year.toYear(context), @@ -143,6 +143,18 @@ fun TextView.bindAlbumDetails(album: Album) { ) } +@BindingAdapter("albumInfo") +fun TextView.bindAlbumInfo(album: Album) { + text = context.getString( + R.string.format_info, + album.artist.name, + context.resources.getQuantityString( + R.plurals.format_song_count, + album.numSongs, album.numSongs + ) + ) +} + @BindingAdapter("albumYear") fun TextView.bindAlbumDate(album: Album) { text = album.year.toYear(context) diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt b/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt index 45c7d362b..d52f25349 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt @@ -4,7 +4,7 @@ import androidx.recyclerview.widget.DiffUtil import org.oxycblt.auxio.music.BaseModel // RecyclerView click listener -class ClickListener(val onClick: (T) -> Unit) +class ClickListener(val onClick: (T) -> Unit) // Base Diff callback class DiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/BaseViewHolder.kt similarity index 84% rename from app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt rename to app/src/main/java/org/oxycblt/auxio/recycler/viewholders/BaseViewHolder.kt index 2382b89fc..62eb6fe61 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/BaseViewHolder.kt @@ -1,10 +1,12 @@ -package org.oxycblt.auxio.recycler +package org.oxycblt.auxio.recycler.viewholders import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView 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. +// TODO: Implement some kind of abstraction for BaseViewHolder.from() abstract class BaseViewHolder( private val baseBinding: ViewDataBinding, protected val listener: ClickListener? diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt new file mode 100644 index 000000000..cf5fa7c96 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt @@ -0,0 +1,127 @@ +package org.oxycblt.auxio.recycler.viewholders + +import android.content.Context +import android.view.LayoutInflater +import org.oxycblt.auxio.databinding.ItemAlbumBinding +import org.oxycblt.auxio.databinding.ItemArtistBinding +import org.oxycblt.auxio.databinding.ItemGenreBinding +import org.oxycblt.auxio.databinding.ItemHeaderBinding +import org.oxycblt.auxio.databinding.ItemSongBinding +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.Header +import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.recycler.ClickListener + +// Basic ViewHolders for each music model. +// FIXME: Mode these type signaturs to something sensible. + +class GenreViewHolder private constructor( + listener: ClickListener, + private val binding: ItemGenreBinding +) : BaseViewHolder(binding, listener) { + + override fun onBind(model: BaseModel) { + binding.genre = model as Genre + binding.genreName.requestLayout() + } + + companion object { + const val ITEM_TYPE = 10 + + fun from(context: Context, listener: ClickListener): GenreViewHolder { + return GenreViewHolder( + ClickListener { listener.onClick(it) }, + ItemGenreBinding.inflate(LayoutInflater.from(context)) + ) + } + } +} + +class ArtistViewHolder private constructor( + listener: ClickListener, + private val binding: ItemArtistBinding +) : BaseViewHolder(binding, listener) { + + override fun onBind(model: BaseModel) { + binding.artist = model as Artist + binding.artistName.requestLayout() + } + + companion object { + const val ITEM_TYPE = 11 + + fun from(context: Context, listener: ClickListener): ArtistViewHolder { + return ArtistViewHolder( + ClickListener { listener.onClick(it) }, + ItemArtistBinding.inflate(LayoutInflater.from(context)) + ) + } + } +} + +class AlbumViewHolder private constructor( + listener: ClickListener, + private val binding: ItemAlbumBinding +) : BaseViewHolder(binding, listener) { + + override fun onBind(model: BaseModel) { + binding.album = model as Album + binding.albumName.requestLayout() + } + + companion object { + const val ITEM_TYPE = 12 + + fun from(context: Context, listener: ClickListener): AlbumViewHolder { + return AlbumViewHolder( + listener, + ItemAlbumBinding.inflate(LayoutInflater.from(context)) + ) + } + } +} + +class SongViewHolder private constructor( + listener: ClickListener, + private val binding: ItemSongBinding +) : BaseViewHolder(binding, listener) { + + override fun onBind(model: BaseModel) { + binding.song = model as Song + + binding.songName.requestLayout() + binding.songInfo.requestLayout() + } + + companion object { + const val ITEM_TYPE = 13 + + fun from(context: Context, listener: ClickListener): SongViewHolder { + return SongViewHolder( + listener, + ItemSongBinding.inflate(LayoutInflater.from(context)) + ) + } + } +} + +class HeaderViewHolder( + private val binding: ItemHeaderBinding +) : BaseViewHolder(binding, null) { + override fun onBind(model: BaseModel) { + binding.header = model as Header + } + + companion object { + const val ITEM_TYPE = 14 + + fun from(context: Context): HeaderViewHolder { + return HeaderViewHolder( + ItemHeaderBinding.inflate(LayoutInflater.from(context)) + ) + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongAdapter.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongAdapter.kt index 89c92f3ad..e56bfbb44 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongAdapter.kt @@ -5,8 +5,8 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.ClickListener +import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder class SongAdapter( private val data: List, diff --git a/app/src/main/java/org/oxycblt/auxio/theme/PrefConstants.kt b/app/src/main/java/org/oxycblt/auxio/theme/PrefConstants.kt index 4681a2888..516fb21ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/theme/PrefConstants.kt +++ b/app/src/main/java/org/oxycblt/auxio/theme/PrefConstants.kt @@ -1,6 +1,7 @@ package org.oxycblt.auxio.theme // Preference Constants +// TODO: Move these to dedicated enum class. const val SHOW_ARTISTS = 0 const val SHOW_ALBUMS = 1 const val SHOW_GENRES = 2 diff --git a/app/src/main/res/layout/item_album.xml b/app/src/main/res/layout/item_album.xml index 8ddb578c8..b1145a7f1 100644 --- a/app/src/main/res/layout/item_album.xml +++ b/app/src/main/res/layout/item_album.xml @@ -39,7 +39,7 @@ android:textColor="?android:attr/textColorPrimary" android:ellipsize="end" android:maxLines="1" - app:layout_constraintBottom_toTopOf="@+id/album_song_count" + app:layout_constraintBottom_toTopOf="@+id/album_info" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/album_cover" app:layout_constraintTop_toTopOf="parent" @@ -47,14 +47,14 @@ tools:text="Album Name" />