Refactor genre UI
Fully refactor the genre UI so that it makes more sense.
This commit is contained in:
parent
6e5bff3bd3
commit
51a5e9fd63
20 changed files with 116 additions and 101 deletions
|
@ -84,7 +84,8 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.action_play -> {
|
|
||||||
|
R.id.action_play_albums -> {
|
||||||
playbackModel.playArtist(
|
playbackModel.playArtist(
|
||||||
detailModel.currentArtist.value!!, false
|
detailModel.currentArtist.value!!, false
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.setupSongActions
|
import org.oxycblt.auxio.ui.setupGenreSongActions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [DetailFragment] for a genre.
|
* The [DetailFragment] for a genre.
|
||||||
|
@ -51,7 +51,7 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
playbackModel.playSong(it, PlaybackMode.IN_GENRE)
|
playbackModel.playSong(it, PlaybackMode.IN_GENRE)
|
||||||
},
|
},
|
||||||
doOnLongClick = { data, view ->
|
doOnLongClick = { data, view ->
|
||||||
PopupMenu(requireContext(), view).setupSongActions(
|
PopupMenu(requireContext(), view).setupGenreSongActions(
|
||||||
requireContext(), data, playbackModel
|
requireContext(), data, playbackModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -78,13 +78,6 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.action_play -> {
|
|
||||||
playbackModel.playGenre(
|
|
||||||
detailModel.currentGenre.value!!, false
|
|
||||||
)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,12 +161,12 @@ data class Genre(
|
||||||
private val mSongs = mutableListOf<Song>()
|
private val mSongs = mutableListOf<Song>()
|
||||||
val songs: List<Song> get() = mSongs
|
val songs: List<Song> get() = mSongs
|
||||||
|
|
||||||
val albumCount: Int by lazy {
|
val totalDuration: String by lazy {
|
||||||
songs.groupBy { it.album }.size
|
var seconds: Long = 0
|
||||||
|
songs.forEach {
|
||||||
|
seconds += it.seconds
|
||||||
}
|
}
|
||||||
|
seconds.toDuration()
|
||||||
val artistCount: Int by lazy {
|
|
||||||
songs.groupBy { it.album.artist }.size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addSong(song: Song) {
|
fun addSong(song: Song) {
|
||||||
|
|
|
@ -105,37 +105,6 @@ fun Int.toYear(context: Context): String {
|
||||||
|
|
||||||
// --- BINDING ADAPTERS ---
|
// --- BINDING ADAPTERS ---
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind the artist + album counts for a genre
|
|
||||||
*/
|
|
||||||
@BindingAdapter("genreCounts")
|
|
||||||
fun TextView.bindGenreCounts(genre: Genre) {
|
|
||||||
val artists = context.resources.getQuantityString(
|
|
||||||
R.plurals.format_artist_count, genre.artistCount, genre.artistCount
|
|
||||||
)
|
|
||||||
val albums = context.resources.getQuantityString(
|
|
||||||
R.plurals.format_album_count, genre.albumCount, genre.albumCount
|
|
||||||
)
|
|
||||||
|
|
||||||
text = context.getString(R.string.format_double_counts, artists, albums)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind the album + song counts for a genre
|
|
||||||
*/
|
|
||||||
@BindingAdapter("altGenreCounts")
|
|
||||||
fun TextView.bindAltGenreCounts(genre: Genre) {
|
|
||||||
val albums = context.resources.getQuantityString(
|
|
||||||
R.plurals.format_album_count, genre.albumCount, genre.albumCount
|
|
||||||
)
|
|
||||||
|
|
||||||
val songs = context.resources.getQuantityString(
|
|
||||||
R.plurals.format_song_count, genre.songs.size, genre.songs.size
|
|
||||||
)
|
|
||||||
|
|
||||||
text = context.getString(R.string.format_double_counts, albums, songs)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the most prominent artist genre
|
* Bind the most prominent artist genre
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.oxycblt.auxio.music.processing
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.Albums
|
import android.provider.MediaStore.Audio.Albums
|
||||||
import android.provider.MediaStore.Audio.Genres
|
import android.provider.MediaStore.Audio.Genres
|
||||||
import android.provider.MediaStore.Audio.Media
|
import android.provider.MediaStore.Audio.Media
|
||||||
|
@ -16,7 +17,8 @@ import org.oxycblt.auxio.music.toAlbumArtURI
|
||||||
import org.oxycblt.auxio.music.toNamedGenre
|
import org.oxycblt.auxio.music.toNamedGenre
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that loads music from the filesystem.
|
* Class that loads/constructs [Genre]s, [Album]s, and [Song] objects from the filesystem
|
||||||
|
* Artists are constructed in [MusicSorter], as they are only really containers for [Album]s
|
||||||
*/
|
*/
|
||||||
class MusicLoader(private val app: Application) {
|
class MusicLoader(private val app: Application) {
|
||||||
var genres = mutableListOf<Genre>()
|
var genres = mutableListOf<Genre>()
|
||||||
|
@ -117,10 +119,14 @@ class MusicLoader(private val app: Application) {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val id = cursor.getLong(idIndex)
|
val id = cursor.getLong(idIndex)
|
||||||
val name = cursor.getString(nameIndex) ?: albumPlaceholder
|
val name = cursor.getString(nameIndex) ?: albumPlaceholder
|
||||||
val artistName = cursor.getString(artistIdIndex) ?: artistPlaceholder
|
var artistName = cursor.getString(artistIdIndex) ?: artistPlaceholder
|
||||||
val year = cursor.getInt(yearIndex)
|
val year = cursor.getInt(yearIndex)
|
||||||
val coverUri = id.toAlbumArtURI()
|
val coverUri = id.toAlbumArtURI()
|
||||||
|
|
||||||
|
if (artistName == MediaStore.UNKNOWN_STRING) {
|
||||||
|
artistName = artistPlaceholder
|
||||||
|
}
|
||||||
|
|
||||||
albums.add(
|
albums.add(
|
||||||
Album(
|
Album(
|
||||||
id = id, name = name, artistName = artistName,
|
id = id, name = name, artistName = artistName,
|
||||||
|
@ -192,9 +198,7 @@ class MusicLoader(private val app: Application) {
|
||||||
for (genre in genres) {
|
for (genre in genres) {
|
||||||
val songGenreCursor = resolver.query(
|
val songGenreCursor = resolver.query(
|
||||||
Genres.Members.getContentUri("external", genre.id),
|
Genres.Members.getContentUri("external", genre.id),
|
||||||
arrayOf(
|
arrayOf(Genres.Members._ID),
|
||||||
Genres.Members._ID
|
|
||||||
),
|
|
||||||
null, null, null
|
null, null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package org.oxycblt.auxio.music.processing
|
package org.oxycblt.auxio.music.processing
|
||||||
|
|
||||||
import org.oxycblt.auxio.logD
|
|
||||||
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.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object responsible for creating [Artist]s from [Album]s and generally sorting everything.
|
||||||
|
*/
|
||||||
class MusicSorter(
|
class MusicSorter(
|
||||||
val songs: MutableList<Song>,
|
val songs: MutableList<Song>,
|
||||||
val albums: MutableList<Album>
|
val albums: MutableList<Album>
|
||||||
|
@ -27,7 +29,6 @@ class MusicSorter(
|
||||||
val groupedAlbums = albums.groupBy { it.artistName }
|
val groupedAlbums = albums.groupBy { it.artistName }
|
||||||
|
|
||||||
groupedAlbums.forEach {
|
groupedAlbums.forEach {
|
||||||
logD(it.key)
|
|
||||||
artists.add(
|
artists.add(
|
||||||
Artist(id = artists.size.toLong(), name = it.key, albums = it.value)
|
Artist(id = artists.size.toLong(), name = it.key, albums = it.value)
|
||||||
)
|
)
|
||||||
|
|
|
@ -507,15 +507,13 @@ class PlaybackStateManager private constructor() {
|
||||||
* @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations caused by the above parameter.
|
* @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations caused by the above parameter.
|
||||||
*/
|
*/
|
||||||
private fun genShuffle(keepSong: Boolean, useLastSong: Boolean = false) {
|
private fun genShuffle(keepSong: Boolean, useLastSong: Boolean = false) {
|
||||||
val newSeed = Random.Default.nextLong()
|
mShuffleSeed = Random.Default.nextLong()
|
||||||
|
|
||||||
logD("Shuffling queue with seed $newSeed")
|
logD("Shuffling queue with seed $mShuffleSeed")
|
||||||
|
|
||||||
val lastSong = if (useLastSong) mQueue[mIndex] else mSong
|
val lastSong = if (useLastSong) mQueue[mIndex] else mSong
|
||||||
|
|
||||||
mShuffleSeed = newSeed
|
mQueue.shuffle(Random(mShuffleSeed))
|
||||||
|
|
||||||
mQueue.shuffle(Random(newSeed))
|
|
||||||
mIndex = 0
|
mIndex = 0
|
||||||
|
|
||||||
// If specified, make the current song the first member of the queue.
|
// If specified, make the current song the first member of the queue.
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.oxycblt.auxio.ui.ACCENTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
|
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
|
||||||
|
* TODO: Add option to play song from genre, now that its possible
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
class SettingsManager private constructor(context: Context) :
|
class SettingsManager private constructor(context: Context) :
|
||||||
|
|
|
@ -197,7 +197,7 @@ fun PopupMenu.setupAlbumActions(
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inflateAndShow(R.menu.menu_album_actions)
|
inflateAndShow(R.menu.menu_album_detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,7 +221,7 @@ fun PopupMenu.setupArtistActions(artist: Artist, playbackModel: PlaybackViewMode
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inflateAndShow(R.menu.menu_detail)
|
inflateAndShow(R.menu.menu_artist_detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,11 +232,6 @@ fun PopupMenu.setupArtistActions(artist: Artist, playbackModel: PlaybackViewMode
|
||||||
fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel) {
|
fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel) {
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.action_play -> {
|
|
||||||
playbackModel.playGenre(genre, false)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_shuffle -> {
|
R.id.action_shuffle -> {
|
||||||
playbackModel.playGenre(genre, true)
|
playbackModel.playGenre(genre, true)
|
||||||
true
|
true
|
||||||
|
@ -245,7 +240,43 @@ fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inflateAndShow(R.menu.menu_detail)
|
inflateAndShow(R.menu.menu_artist_detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show actions for a song in a genre.
|
||||||
|
* @param context [Context] required
|
||||||
|
* @param song [Song] the menu should correspond to
|
||||||
|
* @param playbackModel [PlaybackViewModel] to dispatch actions to
|
||||||
|
*/
|
||||||
|
fun PopupMenu.setupGenreSongActions(context: Context, song: Song, playbackModel: PlaybackViewModel) {
|
||||||
|
setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.action_queue_add -> {
|
||||||
|
playbackModel.addToUserQueue(song)
|
||||||
|
context.getString(R.string.label_queue_added).createToast(context)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_play_artist -> {
|
||||||
|
playbackModel.playSong(song, PlaybackMode.IN_ARTIST)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_play_album -> {
|
||||||
|
playbackModel.playSong(song, PlaybackMode.IN_ALBUM)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_play_all_songs -> {
|
||||||
|
playbackModel.playSong(song, PlaybackMode.ALL_SONGS)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inflateAndShow(R.menu.menu_genre_song_actions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_album_actions"
|
app:menu="@menu/menu_album_detail"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_detail"
|
app:menu="@menu/menu_artist_detail"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_detail"
|
app:menu="@menu/menu_songs"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
android:text="@{genre.name}"
|
android:text="@{genre.name}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/genre_counts"
|
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
||||||
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"
|
||||||
|
@ -70,30 +70,30 @@
|
||||||
tools:text="Genre Name" />
|
tools:text="Genre Name" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_counts"
|
android:id="@+id/genre_song_count"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
app:genreCounts="@{genre}"
|
android:text="@{@plurals/format_song_count(genre.songs.size(), genre.songs.size())}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
app:layout_constraintBottom_toTopOf="@+id/genre_duration"
|
||||||
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
||||||
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" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_song_count"
|
android:id="@+id/genre_duration"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:text="@{@plurals/format_song_count(genre.songs.size, genre.songs.size)}"
|
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_toTopOf="@+id/genre_song_header"
|
||||||
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_counts"
|
app:layout_constraintTop_toBottomOf="@+id/genre_song_count"
|
||||||
tools:text="80 Songs" />
|
tools:text="16:16" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_song_header"
|
android:id="@+id/genre_song_header"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_album_actions"
|
app:menu="@menu/menu_album_detail"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_detail"
|
app:menu="@menu/menu_artist_detail"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
style="@style/Toolbar.Style.Icon"
|
style="@style/Toolbar.Style.Icon"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:elevation="@dimen/elevation_normal"
|
android:elevation="@dimen/elevation_normal"
|
||||||
app:menu="@menu/menu_detail"
|
app:menu="@menu/menu_songs"
|
||||||
app:title="@string/label_library" />
|
app:title="@string/label_library" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
@ -70,29 +70,29 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_image"
|
app:layout_constraintTop_toBottomOf="@+id/genre_image"
|
||||||
tools:text="Genre Name" />
|
tools:text="Genre Name" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/genre_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:genreCounts="@{genre}"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_name"
|
|
||||||
tools:text="2 Artists, 4 Albums" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_song_count"
|
android:id="@+id/genre_song_count"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:text="@{@plurals/format_song_count(genre.songs.size, genre.songs.size)}"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:text="@{@plurals/format_song_count(genre.songs.size(), genre.songs.size())}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/genre_name"
|
||||||
|
tools:text="80 Songs" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/genre_duration"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
|
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_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_counts"
|
app:layout_constraintTop_toBottomOf="@+id/genre_song_count"
|
||||||
tools:text="80 Songs" />
|
tools:text="16:16" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_song_header"
|
android:id="@+id/genre_song_header"
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
android:layout_marginTop="@dimen/padding_medium"
|
android:layout_marginTop="@dimen/padding_medium"
|
||||||
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_song_count" />
|
app:layout_constraintTop_toBottomOf="@+id/genre_duration" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/genre_sort_button"
|
android:id="@+id/genre_sort_button"
|
||||||
|
|
|
@ -38,12 +38,12 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_count"
|
android:id="@+id/genre_count"
|
||||||
style="@style/ItemText.Secondary"
|
style="@style/ItemText.Secondary"
|
||||||
app:altGenreCounts="@{genre}"
|
android:text="@{@plurals/format_song_count(genre.songs.size(), genre.songs.size())}"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_name"
|
app:layout_constraintTop_toBottomOf="@+id/genre_name"
|
||||||
tools:text="4 Albums, 40 Songs" />
|
tools:text="40 Songs" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -7,8 +7,8 @@
|
||||||
android:title="@string/label_shuffle"
|
android:title="@string/label_shuffle"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_play"
|
android:id="@+id/action_play_albums"
|
||||||
android:icon="@drawable/ic_play"
|
android:icon="@drawable/ic_play"
|
||||||
android:title="@string/label_play"
|
android:title="@string/label_play_albums"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
15
app/src/main/res/menu/menu_genre_song_actions.xml
Normal file
15
app/src/main/res/menu/menu_genre_song_actions.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_queue_add"
|
||||||
|
android:icon="@drawable/ic_queue_add"
|
||||||
|
android:title="@string/label_queue_add" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_play_artist"
|
||||||
|
android:icon="@drawable/ic_artist"
|
||||||
|
android:title="@string/label_play_artist" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_play_album"
|
||||||
|
android:icon="@drawable/ic_album"
|
||||||
|
android:title="@string/label_play_album" />
|
||||||
|
</menu>
|
|
@ -28,6 +28,8 @@
|
||||||
<string name="label_play_album">Play from album</string>
|
<string name="label_play_album">Play from album</string>
|
||||||
<string name="label_play_artist">Play from artist</string>
|
<string name="label_play_artist">Play from artist</string>
|
||||||
<string name="label_go_artist">Go to artist</string>
|
<string name="label_go_artist">Go to artist</string>
|
||||||
|
<string name="label_play_albums">Play albums</string>
|
||||||
|
<string name="label_shuffle_albums">Shuffle albums</string>
|
||||||
|
|
||||||
<string name="label_queue">Queue</string>
|
<string name="label_queue">Queue</string>
|
||||||
<string name="label_queue_add">Add to queue</string>
|
<string name="label_queue_add">Add to queue</string>
|
||||||
|
|
Loading…
Reference in a new issue