Move play & shuffle to dedicated buttons

Move the play and shuffle actions to dedicated buttons on the DetailFragments. Actually looks r e a l l y nice.
This commit is contained in:
OxygenCobalt 2021-01-03 10:16:23 -07:00
parent 0bcf228496
commit 260e7f71cf
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 303 additions and 85 deletions

View file

@ -44,7 +44,7 @@ class AlbumDetailFragment : DetailFragment() {
} }
val detailAdapter = AlbumDetailAdapter( val detailAdapter = AlbumDetailAdapter(
detailModel, viewLifecycleOwner, detailModel, playbackModel, viewLifecycleOwner,
doOnClick = { playbackModel.playSong(it, PlaybackMode.IN_ALBUM) }, doOnClick = { playbackModel.playSong(it, PlaybackMode.IN_ALBUM) },
doOnLongClick = { data, view -> doOnLongClick = { data, view ->
PopupMenu(requireContext(), view).setupAlbumSongActions( PopupMenu(requireContext(), view).setupAlbumSongActions(
@ -57,23 +57,8 @@ class AlbumDetailFragment : DetailFragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
setupToolbar(R.menu.menu_album_actions) { setupToolbar(R.menu.menu_album_detail) {
when (it) { when (it) {
R.id.action_shuffle -> {
playbackModel.playAlbum(
detailModel.currentAlbum.value!!, true
)
true
}
R.id.action_play -> {
playbackModel.playAlbum(
detailModel.currentAlbum.value!!, false
)
true
}
R.id.action_queue_add -> { R.id.action_queue_add -> {
playbackModel.addToUserQueue(detailModel.currentAlbum.value!!) playbackModel.addToUserQueue(detailModel.currentAlbum.value!!)
getString(R.string.label_queue_added).createToast(requireContext()) getString(R.string.label_queue_added).createToast(requireContext())

View file

@ -7,7 +7,6 @@ import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
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.detail.adapters.ArtistDetailAdapter import org.oxycblt.auxio.detail.adapters.ArtistDetailAdapter
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
@ -43,7 +42,7 @@ class ArtistDetailFragment : DetailFragment() {
} }
val detailAdapter = ArtistDetailAdapter( val detailAdapter = ArtistDetailAdapter(
detailModel, viewLifecycleOwner, detailModel, playbackModel, viewLifecycleOwner,
doOnClick = { doOnClick = {
if (!detailModel.isNavigating) { if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true) detailModel.updateNavigationStatus(true)
@ -64,29 +63,7 @@ class ArtistDetailFragment : DetailFragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
setupToolbar(R.menu.menu_artist_actions) { setupToolbar()
when (it) {
R.id.action_shuffle -> {
playbackModel.playArtist(
detailModel.currentArtist.value!!,
true
)
true
}
R.id.action_play_albums -> {
playbackModel.playArtist(
detailModel.currentArtist.value!!, false
)
true
}
else -> false
}
}
setupRecycler(detailAdapter) setupRecycler(detailAdapter)
// --- VIEWMODEL SETUP --- // --- VIEWMODEL SETUP ---

View file

@ -47,16 +47,23 @@ abstract class DetailFragment : Fragment() {
/** /**
* Shortcut method for doing setup of the detail toolbar. * Shortcut method for doing setup of the detail toolbar.
*/ */
protected fun setupToolbar(@MenuRes menu: Int, onMenuClick: (id: Int) -> Boolean) { protected fun setupToolbar(
@MenuRes menu: Int = -1,
onMenuClick: ((id: Int) -> Boolean)? = null
) {
binding.detailToolbar.apply { binding.detailToolbar.apply {
inflateMenu(menu) if (menu != -1) {
inflateMenu(menu)
}
setNavigationOnClickListener { setNavigationOnClickListener {
findNavController().navigateUp() findNavController().navigateUp()
} }
setOnMenuItemClickListener { onMenuClick?.let {
onMenuClick(it.itemId) setOnMenuItemClickListener {
it(it.itemId)
}
} }
} }
} }

View file

@ -7,7 +7,6 @@ import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
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.detail.adapters.GenreDetailAdapter import org.oxycblt.auxio.detail.adapters.GenreDetailAdapter
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
@ -42,7 +41,7 @@ class GenreDetailFragment : DetailFragment() {
} }
val detailAdapter = GenreDetailAdapter( val detailAdapter = GenreDetailAdapter(
detailModel, viewLifecycleOwner, detailModel, playbackModel, viewLifecycleOwner,
doOnClick = { doOnClick = {
playbackModel.playSong(it, PlaybackMode.IN_GENRE) playbackModel.playSong(it, PlaybackMode.IN_GENRE)
}, },
@ -57,21 +56,7 @@ class GenreDetailFragment : DetailFragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
setupToolbar(R.menu.menu_genre_actions) { setupToolbar()
when (it) {
R.id.action_shuffle -> {
playbackModel.playGenre(
detailModel.currentGenre.value!!,
true
)
true
}
else -> false
}
}
setupRecycler(detailAdapter) setupRecycler(detailAdapter)
// --- DETAILVIEWMODEL SETUP --- // --- DETAILVIEWMODEL SETUP ---

View file

@ -1,29 +1,34 @@
package org.oxycblt.auxio.detail.adapters package org.oxycblt.auxio.detail.adapters
import android.content.res.ColorStateList
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.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.R
import org.oxycblt.auxio.databinding.ItemAlbumHeaderBinding import org.oxycblt.auxio.databinding.ItemAlbumHeaderBinding
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
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.recycler.viewholders.Highlightable import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.disable import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource import org.oxycblt.auxio.ui.setTextColorResource
import org.oxycblt.auxio.ui.toColor
/** /**
* An adapter for displaying the details and [Song]s of an [Album] * An adapter for displaying the details and [Song]s of an [Album]
*/ */
class AlbumDetailAdapter( class AlbumDetailAdapter(
private val detailModel: DetailViewModel, private val detailModel: DetailViewModel,
private val playbackModel: PlaybackViewModel,
private val lifecycleOwner: LifecycleOwner, 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
@ -109,8 +114,25 @@ class AlbumDetailAdapter(
override fun onBind(data: Album) { override fun onBind(data: Album) {
binding.album = data binding.album = data
binding.detailModel = detailModel binding.detailModel = detailModel
binding.playbackModel = playbackModel
binding.lifecycleOwner = lifecycleOwner binding.lifecycleOwner = lifecycleOwner
// Apply the accent programmatically since I don't want to deal the with the
// nightmarish mess of switching out my styling to Material
val accent = accent.first.toColor(binding.albumShuffleButton.context)
val selection = ColorStateList.valueOf(
R.color.selection_color.toColor(binding.albumShuffleButton.context)
)
binding.albumShuffleButton.apply {
backgroundTintList = ColorStateList.valueOf(accent)
rippleColor = selection
}
binding.albumPlayButton.apply {
setTextColor(accent)
rippleColor = selection
}
if (data.songs.size < 2) { if (data.songs.size < 2) {
binding.albumSortButton.disable() binding.albumSortButton.disable()
} }

View file

@ -1,29 +1,34 @@
package org.oxycblt.auxio.detail.adapters package org.oxycblt.auxio.detail.adapters
import android.content.res.ColorStateList
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.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.R
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.databinding.ItemArtistHeaderBinding import org.oxycblt.auxio.databinding.ItemArtistHeaderBinding
import org.oxycblt.auxio.detail.DetailViewModel 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.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.playback.PlaybackViewModel
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.recycler.viewholders.Highlightable import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.disable import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource import org.oxycblt.auxio.ui.setTextColorResource
import org.oxycblt.auxio.ui.toColor
/** /**
* An adapter for displaying the [Album]s of an artist. * An adapter for displaying the [Album]s of an artist.
*/ */
class ArtistDetailAdapter( class ArtistDetailAdapter(
private val detailModel: DetailViewModel, private val detailModel: DetailViewModel,
private val playbackModel: PlaybackViewModel,
private val lifecycleOwner: LifecycleOwner, 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,
@ -108,8 +113,26 @@ class ArtistDetailAdapter(
override fun onBind(data: Artist) { override fun onBind(data: Artist) {
binding.artist = data binding.artist = data
binding.detailModel = detailModel binding.detailModel = detailModel
binding.playbackModel = playbackModel
binding.lifecycleOwner = lifecycleOwner binding.lifecycleOwner = lifecycleOwner
// Apply the accent programmatically since I don't want to deal the with the
// nightmarish mess of switching out my styling to Material
val accent = accent.first.toColor(binding.artistShuffleButton.context)
val selection = ColorStateList.valueOf(
R.color.selection_color.toColor(binding.artistShuffleButton.context)
)
binding.artistShuffleButton.apply {
backgroundTintList = ColorStateList.valueOf(accent)
rippleColor = selection
}
binding.artistPlayButton.apply {
setTextColor(accent)
rippleColor = selection
}
if (data.albums.size < 2) { if (data.albums.size < 2) {
binding.artistSortButton.disable() binding.artistSortButton.disable()
} }

View file

@ -1,29 +1,34 @@
package org.oxycblt.auxio.detail.adapters package org.oxycblt.auxio.detail.adapters
import android.content.res.ColorStateList
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.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.R
import org.oxycblt.auxio.databinding.ItemGenreHeaderBinding import org.oxycblt.auxio.databinding.ItemGenreHeaderBinding
import org.oxycblt.auxio.databinding.ItemGenreSongBinding import org.oxycblt.auxio.databinding.ItemGenreSongBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
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.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
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.recycler.viewholders.Highlightable import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.disable import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource import org.oxycblt.auxio.ui.setTextColorResource
import org.oxycblt.auxio.ui.toColor
/** /**
* An adapter for displaying the [Song]s of a genre. * An adapter for displaying the [Song]s of a genre.
*/ */
class GenreDetailAdapter( class GenreDetailAdapter(
private val detailModel: DetailViewModel, private val detailModel: DetailViewModel,
private val playbackModel: PlaybackViewModel,
private val lifecycleOwner: LifecycleOwner, 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
@ -109,8 +114,26 @@ class GenreDetailAdapter(
override fun onBind(data: Genre) { override fun onBind(data: Genre) {
binding.genre = data binding.genre = data
binding.detailModel = detailModel binding.detailModel = detailModel
binding.playbackModel = playbackModel
binding.lifecycleOwner = lifecycleOwner binding.lifecycleOwner = lifecycleOwner
// Apply the accent programmatically since I don't want to deal the with the
// nightmarish mess of switching out my styling to Material
val accent = accent.first.toColor(binding.genreShuffleButton.context)
val selection = ColorStateList.valueOf(
R.color.selection_color.toColor(binding.genreShuffleButton.context)
)
binding.genreShuffleButton.apply {
backgroundTintList = ColorStateList.valueOf(accent)
rippleColor = selection
}
binding.genrePlayButton.apply {
setTextColor(accent)
rippleColor = selection
}
if (data.songs.size < 2) { if (data.songs.size < 2) {
binding.genreSortButton.disable() binding.genreSortButton.disable()
} }

View file

@ -5,13 +5,17 @@
<data> <data>
<variable
name="album"
type="org.oxycblt.auxio.music.Album" />
<variable <variable
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable <variable
name="album" name="playbackModel"
type="org.oxycblt.auxio.music.Album" /> type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -43,7 +47,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/album_cover" app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@+id/album_cover"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="Album Name" /> tools:text="Album Name" />
@ -72,18 +76,40 @@
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:albumDetails="@{album}" app:albumDetails="@{album}"
app:layout_constraintBottom_toTopOf="@+id/album_song_header" app:layout_constraintBottom_toBottomOf="@+id/album_cover"
app:layout_constraintStart_toEndOf="@+id/album_cover" app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toBottomOf="@+id/album_artist" app:layout_constraintTop_toBottomOf="@+id/album_artist"
tools:text="2020 / 10 Songs / 16:16" /> tools:text="2020 / 10 Songs / 16:16" />
<com.google.android.material.button.MaterialButton
android:id="@+id/album_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playAlbum(album, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/album_shuffle_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_cover"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/album_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playAlbum(album, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/album_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_play_button"
app:layout_constraintTop_toTopOf="@+id/album_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/album_song_header" android:id="@+id/album_song_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="8dp"
android:text="@string/label_songs" android:text="@string/label_songs"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_cover" /> app:layout_constraintTop_toBottomOf="@+id/album_play_button" />
<ImageButton <ImageButton
android:id="@+id/album_sort_button" android:id="@+id/album_sort_button"

View file

@ -13,6 +13,10 @@
<variable <variable
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -42,7 +46,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/artist_image" app:layout_constraintStart_toEndOf="@+id/artist_image"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@+id/artist_image"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="Artist Name" /> tools:text="Artist Name" />
@ -67,18 +71,40 @@
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:artistCounts="@{artist}" app:artistCounts="@{artist}"
app:layout_constraintBottom_toTopOf="@+id/artist_album_header" app:layout_constraintBottom_toBottomOf="@+id/artist_image"
app:layout_constraintStart_toEndOf="@+id/artist_image" app:layout_constraintStart_toEndOf="@+id/artist_image"
app:layout_constraintTop_toBottomOf="@+id/artist_genre" app:layout_constraintTop_toBottomOf="@+id/artist_genre"
tools:text="2 Albums, 20 Songs" /> tools:text="2 Albums, 20 Songs" />
<com.google.android.material.button.MaterialButton
android:id="@+id/artist_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playArtist(artist, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/artist_shuffle_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_image"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/artist_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playArtist(artist, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/artist_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/artist_play_button"
app:layout_constraintTop_toTopOf="@+id/artist_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/artist_album_header" android:id="@+id/artist_album_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_small"
android:text="@string/label_albums" android:text="@string/label_albums"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_image" /> app:layout_constraintTop_toBottomOf="@+id/artist_play_button" />
<ImageButton <ImageButton
android:id="@+id/artist_sort_button" android:id="@+id/artist_sort_button"

View file

@ -14,6 +14,9 @@
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -43,7 +46,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/genre_image" app:layout_constraintStart_toEndOf="@+id/genre_image"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@+id/genre_image"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="Genre Name" /> tools:text="Genre Name" />
@ -60,6 +63,28 @@
app:layout_constraintTop_toBottomOf="@+id/genre_name" app:layout_constraintTop_toBottomOf="@+id/genre_name"
tools:text="2 Artists, 4 Albums" /> tools:text="2 Artists, 4 Albums" />
<com.google.android.material.button.MaterialButton
android:id="@+id/genre_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playGenre(genre, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/genre_shuffle_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/genre_image"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/genre_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playGenre(genre, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/genre_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/genre_play_button"
app:layout_constraintTop_toTopOf="@+id/genre_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/genre_duration" android:id="@+id/genre_duration"
android:layout_width="0dp" android:layout_width="0dp"
@ -68,7 +93,7 @@
android:text="@{genre.totalDuration}" android:text="@{genre.totalDuration}"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toTopOf="@+id/genre_song_header" app:layout_constraintBottom_toBottomOf="@+id/genre_image"
app:layout_constraintStart_toEndOf="@+id/genre_image" app:layout_constraintStart_toEndOf="@+id/genre_image"
app:layout_constraintTop_toBottomOf="@+id/genre_song_count" app:layout_constraintTop_toBottomOf="@+id/genre_song_count"
tools:text="16:16" /> tools:text="16:16" />
@ -76,10 +101,10 @@
<TextView <TextView
android:id="@+id/genre_song_header" android:id="@+id/genre_song_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_small"
android:text="@string/label_songs" android:text="@string/label_songs"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/genre_image" /> app:layout_constraintTop_toBottomOf="@+id/genre_play_button" />
<ImageButton <ImageButton
android:id="@+id/genre_sort_button" android:id="@+id/genre_sort_button"

View file

@ -5,13 +5,17 @@
<data> <data>
<variable
name="album"
type="org.oxycblt.auxio.music.Album" />
<variable <variable
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable <variable
name="album" name="playbackModel"
type="org.oxycblt.auxio.music.Album" /> type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -74,13 +78,35 @@
app:layout_constraintTop_toBottomOf="@+id/album_artist" app:layout_constraintTop_toBottomOf="@+id/album_artist"
tools:text="2020 / 10 Songs / 16:16" /> tools:text="2020 / 10 Songs / 16:16" />
<com.google.android.material.button.MaterialButton
android:id="@+id/album_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playAlbum(album, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/album_shuffle_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_details"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/album_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playAlbum(album, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/album_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_play_button"
app:layout_constraintTop_toTopOf="@+id/album_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/album_song_header" android:id="@+id/album_song_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_small"
android:background="@drawable/ui_header_dividers"
android:text="@string/label_songs" android:text="@string/label_songs"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_details" /> app:layout_constraintTop_toBottomOf="@+id/album_play_button" />
<ImageButton <ImageButton
android:id="@+id/album_sort_button" android:id="@+id/album_sort_button"

View file

@ -13,6 +13,10 @@
<variable <variable
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -70,13 +74,34 @@
app:layout_constraintTop_toBottomOf="@+id/artist_genre" app:layout_constraintTop_toBottomOf="@+id/artist_genre"
tools:text="2 Albums, 20 Songs" /> tools:text="2 Albums, 20 Songs" />
<com.google.android.material.button.MaterialButton
android:id="@+id/artist_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playArtist(artist, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/artist_shuffle_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_counts"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/artist_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playArtist(artist, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/artist_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/artist_play_button"
app:layout_constraintTop_toTopOf="@+id/artist_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/artist_album_header" android:id="@+id/artist_album_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_small"
android:text="@string/label_albums" android:text="@string/label_albums"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_counts" /> app:layout_constraintTop_toBottomOf="@+id/artist_play_button" />
<ImageButton <ImageButton
android:id="@+id/artist_sort_button" android:id="@+id/artist_sort_button"

View file

@ -14,6 +14,10 @@
name="detailModel" name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" /> type="org.oxycblt.auxio.detail.DetailViewModel" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -71,13 +75,34 @@
app:layout_constraintTop_toBottomOf="@+id/genre_song_count" app:layout_constraintTop_toBottomOf="@+id/genre_song_count"
tools:text="16:16" /> tools:text="16:16" />
<com.google.android.material.button.MaterialButton
android:id="@+id/genre_play_button"
style="@style/Widget.MaterialComponents.Button.Unimportant"
android:onClick="@{() -> playbackModel.playGenre(genre, false)}"
android:text="@string/label_play"
app:layout_constraintEnd_toStartOf="@+id/genre_shuffle_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/genre_duration"
tools:textColor="@color/blue" />
<com.google.android.material.button.MaterialButton
android:id="@+id/genre_shuffle_button"
style="@style/Widget.MaterialComponents.Button.Highlighted"
android:onClick="@{() -> playbackModel.playGenre(genre, true)}"
android:text="@string/label_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/genre_play_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/genre_play_button"
app:layout_constraintTop_toTopOf="@+id/genre_play_button"
tools:backgroundTint="@color/blue" />
<TextView <TextView
android:id="@+id/genre_song_header" android:id="@+id/genre_song_header"
style="@style/HeaderText" style="@style/HeaderText"
android:layout_marginTop="@dimen/padding_medium" android:layout_marginTop="@dimen/margin_small"
android:text="@string/label_songs" android:text="@string/label_songs"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/genre_duration" /> app:layout_constraintTop_toBottomOf="@+id/genre_play_button" />
<ImageButton <ImageButton
android:id="@+id/genre_sort_button" android:id="@+id/genre_sort_button"

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_queue_add"
android:icon="@drawable/ic_queue_add"
android:title="@string/label_queue_add"
app:showAsAction="never" />
</menu>

View file

@ -180,4 +180,38 @@
<style name="Theme.BottomSheetHeightFix" parent="Widget.Design.BottomSheet.Modal"> <style name="Theme.BottomSheetHeightFix" parent="Widget.Design.BottomSheet.Modal">
<item name="behavior_peekHeight">500dp</item> <item name="behavior_peekHeight">500dp</item>
</style> </style>
<!-- An "Unimportant" material button, used for the "Play" button -->
<style name="Widget.MaterialComponents.Button.Unimportant" parent="@style/Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">@dimen/margin_small</item>
<item name="android:layout_marginStart">@dimen/margin_medium</item>
<item name="android:layout_marginEnd">@dimen/margin_small</item>
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
<item name="android:theme">@style/Theme.MaterialComponents</item>
<item name="strokeColor">@color/divider_color</item>
<item name="strokeWidth">1dp</item>
<item name="rippleColor">@color/selection_color</item>
<item name="fontFamily">@font/inter_semibold</item>
<item name="textAllCaps">false</item>
<item name="cornerRadius">0dp</item>
</style>
<!-- An highlighted material button, used for the "Shuffle" button -->
<style name="Widget.MaterialComponents.Button.Highlighted" parent="@style/Widget.MaterialComponents.Button.TextButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
<item name="android:layout_marginStart">@dimen/margin_small</item>
<item name="android:layout_marginEnd">@dimen/margin_medium</item>
<item name="android:theme">@style/Theme.MaterialComponents</item>
<item name="rippleColor">@color/selection_color</item>
<item name="fontFamily">@font/inter_semibold</item>
<item name="textAllCaps">false</item>
<item name="android:textColor">@color/background</item>
<item name="cornerRadius">0dp</item>
</style>
</resources> </resources>