Update artist detail layout
Update the artist detail layout so that it also relies on a recyclerview entirely instead of a nestedscrollview.
This commit is contained in:
parent
804db8b0d3
commit
7ef4eb5fde
14 changed files with 266 additions and 300 deletions
|
@ -108,7 +108,7 @@ class AlbumDetailFragment : DetailFragment() {
|
||||||
|
|
||||||
// Don't enable the sort button if there's only one song [or less]
|
// Don't enable the sort button if there's only one song [or less]
|
||||||
if (detailModel.currentAlbum.value!!.songs.size < 2) {
|
if (detailModel.currentAlbum.value!!.songs.size < 2) {
|
||||||
binding.albumSortButton.disable(requireContext())
|
binding.albumSortButton.disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this fragment was created in order to nav to an item, then snap scroll to that item.
|
// If this fragment was created in order to nav to an item, then snap scroll to that item.
|
||||||
|
|
|
@ -9,13 +9,13 @@ import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.ArtistAlbumAdapter
|
import org.oxycblt.auxio.detail.adapters.ArtistAlbumAdapter
|
||||||
import org.oxycblt.auxio.logD
|
import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.disable
|
|
||||||
import org.oxycblt.auxio.ui.setupAlbumActions
|
import org.oxycblt.auxio.ui.setupAlbumActions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,7 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val binding = FragmentArtistDetailBinding.inflate(inflater)
|
val binding = FragmentDetailBinding.inflate(inflater)
|
||||||
|
|
||||||
// If DetailViewModel isn't already storing the artist, get it from MusicStore
|
// If DetailViewModel isn't already storing the artist, get it from MusicStore
|
||||||
// using the ID given by the navigation arguments
|
// using the ID given by the navigation arguments
|
||||||
|
@ -46,6 +46,7 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val albumAdapter = ArtistAlbumAdapter(
|
val albumAdapter = ArtistAlbumAdapter(
|
||||||
|
detailModel, viewLifecycleOwner,
|
||||||
doOnClick = {
|
doOnClick = {
|
||||||
if (!detailModel.isNavigating) {
|
if (!detailModel.isNavigating) {
|
||||||
detailModel.updateNavigationStatus(true)
|
detailModel.updateNavigationStatus(true)
|
||||||
|
@ -65,11 +66,10 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.detailModel = detailModel
|
|
||||||
binding.playbackModel = playbackModel
|
|
||||||
binding.artist = detailModel.currentArtist.value!!
|
|
||||||
|
|
||||||
binding.artistToolbar.apply {
|
binding.detailToolbar.apply {
|
||||||
|
inflateMenu(R.menu.menu_artist_detail)
|
||||||
|
|
||||||
setNavigationOnClickListener {
|
setNavigationOnClickListener {
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
@ -98,12 +98,7 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable the sort button if there is only one album [Or less]
|
binding.detailRecycler.apply {
|
||||||
if (detailModel.currentArtist.value!!.albums.size < 2) {
|
|
||||||
binding.artistSortButton.disable(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.artistAlbumRecycler.apply {
|
|
||||||
adapter = albumAdapter
|
adapter = albumAdapter
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
}
|
}
|
||||||
|
@ -113,13 +108,11 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
detailModel.artistSortMode.observe(viewLifecycleOwner) { mode ->
|
detailModel.artistSortMode.observe(viewLifecycleOwner) { mode ->
|
||||||
logD("Updating sort mode to $mode")
|
logD("Updating sort mode to $mode")
|
||||||
|
|
||||||
// Update the current sort icon
|
val data = mutableListOf<BaseModel>(detailModel.currentArtist.value!!).also {
|
||||||
binding.artistSortButton.setImageResource(mode.iconRes)
|
it.addAll(mode.getSortedAlbumList(detailModel.currentArtist.value!!.albums))
|
||||||
|
}
|
||||||
|
|
||||||
// Then update the sort mode of the album adapter.
|
albumAdapter.submitList(data)
|
||||||
albumAdapter.submitList(
|
|
||||||
mode.getSortedAlbumList(detailModel.currentArtist.value!!.albums)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.navToItem.observe(viewLifecycleOwner) {
|
playbackModel.navToItem.observe(viewLifecycleOwner) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val songAdapter = GenreSongAdapter(
|
val songAdapter = GenreSongAdapter(
|
||||||
viewLifecycleOwner, detailModel,
|
detailModel, viewLifecycleOwner,
|
||||||
doOnClick = {
|
doOnClick = {
|
||||||
playbackModel.playSong(it, PlaybackMode.IN_GENRE)
|
playbackModel.playSong(it, PlaybackMode.IN_GENRE)
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,35 +3,76 @@ package org.oxycblt.auxio.detail.adapters
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
||||||
|
import org.oxycblt.auxio.databinding.ItemArtistHeaderBinding
|
||||||
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
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
|
||||||
|
import org.oxycblt.auxio.ui.disable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter for displaying the [Album]s of an artist.
|
* An adapter for displaying the [Album]s of an artist.
|
||||||
*/
|
*/
|
||||||
class ArtistAlbumAdapter(
|
class ArtistAlbumAdapter(
|
||||||
|
private val detailModel: DetailViewModel,
|
||||||
|
private val lifecycleOwner: LifecycleOwner,
|
||||||
private val doOnClick: (data: Album) -> Unit,
|
private val doOnClick: (data: Album) -> Unit,
|
||||||
private val doOnLongClick: (data: Album, view: View) -> Unit,
|
private val doOnLongClick: (data: Album, view: View) -> Unit,
|
||||||
) : ListAdapter<Album, RecyclerView.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return when (getItem(position)) {
|
||||||
|
is Artist -> ARTIST_HEADER_ITEM_TYPE
|
||||||
|
is Album -> ARTIST_ALBUM_ITEM_TYPE
|
||||||
|
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return AlbumViewHolder(
|
return when (viewType) {
|
||||||
|
ARTIST_HEADER_ITEM_TYPE -> ArtistHeaderViewHolder(
|
||||||
|
ItemArtistHeaderBinding.inflate(LayoutInflater.from(parent.context))
|
||||||
|
)
|
||||||
|
|
||||||
|
ARTIST_ALBUM_ITEM_TYPE -> ArtistAlbumViewHolder(
|
||||||
ItemArtistAlbumBinding.inflate(LayoutInflater.from(parent.context))
|
ItemArtistAlbumBinding.inflate(LayoutInflater.from(parent.context))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
else -> error("Invalid ViewHolder item type $viewType")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
when (val item = getItem(position)) {
|
when (val item = getItem(position)) {
|
||||||
is Album -> (holder as AlbumViewHolder).bind(item)
|
is Artist -> (holder as ArtistHeaderViewHolder).bind(item)
|
||||||
|
is Album -> (holder as ArtistAlbumViewHolder).bind(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ArtistHeaderViewHolder(
|
||||||
|
private val binding: ItemArtistHeaderBinding
|
||||||
|
) : BaseViewHolder<Artist>(binding, null, null) {
|
||||||
|
|
||||||
|
override fun onBind(data: Artist) {
|
||||||
|
binding.artist = data
|
||||||
|
binding.detailModel = detailModel
|
||||||
|
binding.lifecycleOwner = lifecycleOwner
|
||||||
|
|
||||||
|
if (data.albums.size < 2) {
|
||||||
|
binding.artistSortButton.disable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic ViewHolder for a detail album
|
// Generic ViewHolder for a detail album
|
||||||
inner class AlbumViewHolder(
|
inner class ArtistAlbumViewHolder(
|
||||||
private val binding: ItemArtistAlbumBinding,
|
private val binding: ItemArtistAlbumBinding,
|
||||||
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick) {
|
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick) {
|
||||||
|
|
||||||
|
@ -41,4 +82,9 @@ class ArtistAlbumAdapter(
|
||||||
binding.albumName.requestLayout()
|
binding.albumName.requestLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ARTIST_HEADER_ITEM_TYPE = 0xA022
|
||||||
|
const val ARTIST_ALBUM_ITEM_TYPE = 0xA023
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,14 @@ import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
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
|
||||||
|
import org.oxycblt.auxio.ui.disable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter for displaying the [Song]s of a genre.
|
* An adapter for displaying the [Song]s of a genre.
|
||||||
*/
|
*/
|
||||||
class GenreSongAdapter(
|
class GenreSongAdapter(
|
||||||
private val lifecycleOwner: LifecycleOwner,
|
|
||||||
private val detailModel: DetailViewModel,
|
private val detailModel: DetailViewModel,
|
||||||
|
private val lifecycleOwner: LifecycleOwner,
|
||||||
private val doOnClick: (data: Song) -> Unit,
|
private val doOnClick: (data: Song) -> Unit,
|
||||||
private val doOnLongClick: (data: Song, view: View) -> Unit
|
private val doOnLongClick: (data: Song, view: View) -> Unit
|
||||||
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
|
||||||
|
@ -62,6 +63,10 @@ class GenreSongAdapter(
|
||||||
binding.genre = data
|
binding.genre = data
|
||||||
binding.detailModel = detailModel
|
binding.detailModel = detailModel
|
||||||
binding.lifecycleOwner = lifecycleOwner
|
binding.lifecycleOwner = lifecycleOwner
|
||||||
|
|
||||||
|
if (data.songs.size < 2) {
|
||||||
|
binding.genreSortButton.disable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ class LinearCenterScroller(target: Int) : RecyclerView.SmoothScroller() {
|
||||||
return calculateDeltaToFit(top, bottom, start, end)
|
return calculateDeltaToFit(top, bottom, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calcDyToMakeVisible(view: View): Int {
|
fun calcDyToMakeVisible(view: View): Int {
|
||||||
val manager = layoutManager ?: return 0
|
val manager = layoutManager ?: return 0
|
||||||
|
|
||||||
if (!manager.canScrollVertically()) return 0
|
if (!manager.canScrollVertically()) return 0
|
||||||
|
@ -116,9 +116,7 @@ class LinearCenterScroller(target: Int) : RecyclerView.SmoothScroller() {
|
||||||
|
|
||||||
interimTargetDx = (TARGET_SEEK_SCROLL_DIST * scrollVector.x).toInt()
|
interimTargetDx = (TARGET_SEEK_SCROLL_DIST * scrollVector.x).toInt()
|
||||||
interimTargetDy = (TARGET_SEEK_SCROLL_DIST * scrollVector.y).toInt()
|
interimTargetDy = (TARGET_SEEK_SCROLL_DIST * scrollVector.y).toInt()
|
||||||
// To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
|
|
||||||
// interim target. Since we track the distance travelled in onSeekTargetStep callback, it
|
|
||||||
// won't actually scroll more than what we need.
|
|
||||||
action.update(
|
action.update(
|
||||||
(interimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO).toInt(),
|
(interimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO).toInt(),
|
||||||
(interimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO).toInt(),
|
(interimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO).toInt(),
|
||||||
|
|
|
@ -37,9 +37,8 @@ fun MenuItem.applyColor(@ColorInt color: Int) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable an image button.
|
* Disable an image button.
|
||||||
* @param context [Context] required to change the [ImageButton]s color.
|
|
||||||
*/
|
*/
|
||||||
fun ImageButton.disable(context: Context) {
|
fun ImageButton.disable() {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
imageTintList = ColorStateList.valueOf(
|
imageTintList = ColorStateList.valueOf(
|
||||||
R.color.inactive_color.toColor(context)
|
R.color.inactive_color.toColor(context)
|
||||||
|
@ -240,7 +239,7 @@ fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inflateAndShow(R.menu.menu_genre_actions)
|
inflateAndShow(R.menu.menu_genre_detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context=".detail.ArtistDetailFragment">
|
|
||||||
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="artist"
|
|
||||||
type="org.oxycblt.auxio.music.Artist" />
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="detailModel"
|
|
||||||
type="org.oxycblt.auxio.detail.DetailViewModel" />
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="playbackModel"
|
|
||||||
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
|
||||||
android:id="@+id/artist_toolbar"
|
|
||||||
style="@style/Toolbar.Style.Icon"
|
|
||||||
android:background="?android:attr/windowBackground"
|
|
||||||
android:elevation="@dimen/elevation_normal"
|
|
||||||
app:menu="@menu/menu_artist_detail"
|
|
||||||
app:title="@string/label_library" />
|
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:animateLayoutChanges="true">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/artist_image"
|
|
||||||
android:layout_width="@dimen/size_cover_mid_huge"
|
|
||||||
android:layout_height="@dimen/size_cover_mid_huge"
|
|
||||||
android:layout_margin="@dimen/margin_medium"
|
|
||||||
android:contentDescription="@{@string/description_artist_image(artist.name)}"
|
|
||||||
app:artistImage="@{artist}"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:src="@drawable/ic_artist" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_name"
|
|
||||||
style="@style/DetailTitleText"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
|
||||||
android:text="@{artist.name}"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/artist_genre"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
tools:text="Artist Name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_genre"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:artistGenre="@{artist}"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/artist_counts"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_name"
|
|
||||||
tools:text="Genre Name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_counts"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:artistCounts="@{artist}"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/artist_album_header"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_genre"
|
|
||||||
tools:text="2 Albums, 20 Songs" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_album_header"
|
|
||||||
style="@style/HeaderText"
|
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
|
||||||
android:text="@string/label_albums"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_image" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/artist_sort_button"
|
|
||||||
style="@style/HeaderAction"
|
|
||||||
android:contentDescription="@string/description_sort_button"
|
|
||||||
android:onClick="@{() -> detailModel.incrementArtistSortMode()}"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/artist_album_header"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/artist_album_header"
|
|
||||||
tools:src="@drawable/ic_sort_numeric_down" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/artist_album_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:nestedScrollingEnabled="false"
|
|
||||||
android:overScrollMode="never"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_album_header"
|
|
||||||
app:spanCount="2"
|
|
||||||
tools:itemCount="4"
|
|
||||||
tools:listitem="@layout/item_album" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
</layout>
|
|
95
app/src/main/res/layout-land/item_artist_header.xml
Normal file
95
app/src/main/res/layout-land/item_artist_header.xml
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="artist"
|
||||||
|
type="org.oxycblt.auxio.music.Artist" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="detailModel"
|
||||||
|
type="org.oxycblt.auxio.detail.DetailViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/artist_image"
|
||||||
|
android:layout_width="@dimen/size_cover_mid_huge"
|
||||||
|
android:layout_height="@dimen/size_cover_mid_huge"
|
||||||
|
android:layout_margin="@dimen/margin_medium"
|
||||||
|
android:contentDescription="@{@string/description_artist_image(artist.name)}"
|
||||||
|
app:artistImage="@{artist}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@drawable/ic_artist" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_name"
|
||||||
|
style="@style/DetailTitleText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
|
android:text="@{artist.name}"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/artist_genre"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="Artist Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_genre"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
app:artistGenre="@{artist}"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/artist_counts"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_name"
|
||||||
|
tools:text="Genre Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_counts"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
app:artistCounts="@{artist}"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/artist_album_header"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_genre"
|
||||||
|
tools:text="2 Albums, 20 Songs" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_album_header"
|
||||||
|
style="@style/HeaderText"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:text="@string/label_albums"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_image" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/artist_sort_button"
|
||||||
|
style="@style/HeaderAction"
|
||||||
|
android:contentDescription="@string/description_sort_button"
|
||||||
|
android:onClick="@{() -> detailModel.incrementArtistSortMode()}"
|
||||||
|
app:sortIcon="@{detailModel.artistSortMode}"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/artist_album_header"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/artist_album_header"
|
||||||
|
tools:src="@drawable/ic_sort_numeric_down" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -1,130 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context=".detail.ArtistDetailFragment">
|
|
||||||
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="artist"
|
|
||||||
type="org.oxycblt.auxio.music.Artist" />
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="detailModel"
|
|
||||||
type="org.oxycblt.auxio.detail.DetailViewModel" />
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="playbackModel"
|
|
||||||
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
|
||||||
android:id="@+id/artist_toolbar"
|
|
||||||
style="@style/Toolbar.Style.Icon"
|
|
||||||
android:background="?android:attr/windowBackground"
|
|
||||||
android:elevation="@dimen/elevation_normal"
|
|
||||||
app:menu="@menu/menu_artist_detail"
|
|
||||||
app:title="@string/label_library" />
|
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:animateLayoutChanges="true">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/artist_image"
|
|
||||||
android:layout_width="@dimen/size_cover_huge"
|
|
||||||
android:layout_height="@dimen/size_cover_huge"
|
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
|
||||||
android:contentDescription="@{@string/description_artist_image(artist.name)}"
|
|
||||||
app:artistImage="@{artist}"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:src="@drawable/ic_artist" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_name"
|
|
||||||
style="@style/DetailTitleText"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
|
||||||
android:text="@{artist.name}"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_image"
|
|
||||||
tools:text="Artist Name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_genre"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:artistGenre="@{artist}"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_name"
|
|
||||||
tools:text="Genre Name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_counts"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:artistCounts="@{artist}"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_genre"
|
|
||||||
tools:text="2 Albums, 20 Songs" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artist_album_header"
|
|
||||||
style="@style/HeaderText"
|
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
|
||||||
android:text="@string/label_albums"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_counts" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/artist_sort_button"
|
|
||||||
style="@style/HeaderAction"
|
|
||||||
android:contentDescription="@string/description_sort_button"
|
|
||||||
android:onClick="@{() -> detailModel.incrementArtistSortMode()}"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/artist_album_header"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/artist_album_header"
|
|
||||||
tools:src="@drawable/ic_sort_numeric_down" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/artist_album_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:nestedScrollingEnabled="false"
|
|
||||||
android:overScrollMode="never"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_album_header"
|
|
||||||
tools:itemCount="4"
|
|
||||||
tools:listitem="@layout/item_album" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
</layout>
|
|
|
@ -27,6 +27,6 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_song_header"
|
app:layout_constraintTop_toBottomOf="@+id/genre_song_header"
|
||||||
tools:listitem="@layout/item_genre_header" />
|
tools:listitem="@layout/item_artist_header" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
93
app/src/main/res/layout/item_artist_header.xml
Normal file
93
app/src/main/res/layout/item_artist_header.xml
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="artist"
|
||||||
|
type="org.oxycblt.auxio.music.Artist" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="detailModel"
|
||||||
|
type="org.oxycblt.auxio.detail.DetailViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/artist_image"
|
||||||
|
android:layout_width="@dimen/size_cover_huge"
|
||||||
|
android:layout_height="@dimen/size_cover_huge"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:contentDescription="@{@string/description_artist_image(artist.name)}"
|
||||||
|
app:artistImage="@{artist}"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@drawable/ic_artist" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_name"
|
||||||
|
style="@style/DetailTitleText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
|
android:text="@{artist.name}"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_image"
|
||||||
|
tools:text="Artist Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_genre"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
app:artistGenre="@{artist}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_name"
|
||||||
|
tools:text="Genre Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_counts"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
app:artistCounts="@{artist}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_genre"
|
||||||
|
tools:text="2 Albums, 20 Songs" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artist_album_header"
|
||||||
|
style="@style/HeaderText"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:text="@string/label_albums"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/artist_counts" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/artist_sort_button"
|
||||||
|
style="@style/HeaderAction"
|
||||||
|
android:contentDescription="@string/description_sort_button"
|
||||||
|
android:onClick="@{() -> detailModel.incrementArtistSortMode()}"
|
||||||
|
app:sortIcon="@{detailModel.artistSortMode}"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/artist_album_header"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/artist_album_header"
|
||||||
|
tools:src="@drawable/ic_sort_numeric_down" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -35,7 +35,7 @@
|
||||||
android:id="@+id/artist_detail_fragment"
|
android:id="@+id/artist_detail_fragment"
|
||||||
android:name="org.oxycblt.auxio.detail.ArtistDetailFragment"
|
android:name="org.oxycblt.auxio.detail.ArtistDetailFragment"
|
||||||
android:label="ArtistDetailFragment"
|
android:label="ArtistDetailFragment"
|
||||||
tools:layout="@layout/fragment_artist_detail">
|
tools:layout="@layout/fragment_detail">
|
||||||
<argument
|
<argument
|
||||||
android:name="artistId"
|
android:name="artistId"
|
||||||
app:argType="long" />
|
app:argType="long" />
|
||||||
|
|
Loading…
Reference in a new issue