Improve genre loading
Temporarily remove the ability to play from a genre, update MusicLoader to not load genres/artists simultaniously so that Artist ID's arent completely garbled. Improve PlaybackFragment slightly.
This commit is contained in:
parent
c17666752b
commit
339100e436
12 changed files with 81 additions and 154 deletions
|
@ -121,13 +121,13 @@ class AlbumDetailFragment : Fragment() {
|
|||
}
|
||||
|
||||
// Update the play button depending on the current playback status
|
||||
// If the shown album is currently playing, set the button icon to the current isPlaying
|
||||
// status, and then set its behavior to modify isPlaying.
|
||||
// If the shown album isn't currently playing, set the button to Play and its behavior
|
||||
// to start the playback of the album.
|
||||
// If playing this album -> Make button show media controls
|
||||
// If not playing this album -> Make button update playback to the artist
|
||||
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentAlbumDetailBinding) {
|
||||
playbackModel.currentSong.value?.let { song ->
|
||||
if (mode == PlaybackMode.IN_ALBUM && song.album == detailModel.currentAlbum.value) {
|
||||
playbackModel.currentParent.value?.let { parent ->
|
||||
if (mode == PlaybackMode.IN_ALBUM &&
|
||||
parent.id == detailModel.currentAlbum.value!!.id
|
||||
) {
|
||||
if (playbackModel.isPlaying.value!!) {
|
||||
binding.albumPlay.setImageResource(R.drawable.ic_pause)
|
||||
} else {
|
||||
|
|
|
@ -106,14 +106,12 @@ class ArtistDetailFragment : Fragment() {
|
|||
}
|
||||
|
||||
// Update the play button depending on the current playback status
|
||||
// If the shown artist is currently playing, set the button icon to the current isPlaying
|
||||
// status, and then set its behavior to modify isPlaying.
|
||||
// If the shown artist isn't currently playing, set the button to Play and its behavior
|
||||
// to start the playback of the artist.
|
||||
// If playing this artist -> Make button show media controls
|
||||
// If not playing this artist -> Make button update playback to the artist
|
||||
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentArtistDetailBinding) {
|
||||
playbackModel.currentSong.value?.let { song ->
|
||||
playbackModel.currentParent.value?.let { parent ->
|
||||
if (mode == PlaybackMode.IN_ARTIST &&
|
||||
song.album.artist == detailModel.currentArtist.value
|
||||
parent.id == detailModel.currentArtist.value!!.id
|
||||
) {
|
||||
if (playbackModel.isPlaying.value!!) {
|
||||
binding.artistPlay.setImageResource(R.drawable.ic_pause)
|
||||
|
|
|
@ -9,12 +9,9 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
||||
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.playback.PlaybackMode
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.theme.applyDivider
|
||||
import org.oxycblt.auxio.theme.disable
|
||||
|
||||
|
@ -22,7 +19,6 @@ class GenreDetailFragment : Fragment() {
|
|||
|
||||
private val args: GenreDetailFragmentArgs by navArgs()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -57,7 +53,6 @@ class GenreDetailFragment : Fragment() {
|
|||
|
||||
binding.lifecycleOwner = this
|
||||
binding.detailModel = detailModel
|
||||
binding.playbackModel = playbackModel
|
||||
binding.genre = detailModel.currentGenre.value
|
||||
|
||||
binding.genreToolbar.setNavigationOnClickListener {
|
||||
|
@ -89,14 +84,6 @@ class GenreDetailFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
playbackModel.currentMode.observe(viewLifecycleOwner) {
|
||||
updatePlayButton(it, binding)
|
||||
}
|
||||
|
||||
playbackModel.isPlaying.observe(viewLifecycleOwner) {
|
||||
updatePlayButton(playbackModel.currentMode.value!!, binding)
|
||||
}
|
||||
|
||||
Log.d(this::class.simpleName, "Fragment created.")
|
||||
|
||||
return binding.root
|
||||
|
@ -107,27 +94,4 @@ class GenreDetailFragment : Fragment() {
|
|||
|
||||
detailModel.updateNavigationStatus(false)
|
||||
}
|
||||
|
||||
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentGenreDetailBinding) {
|
||||
if (mode == PlaybackMode.IN_GENRE &&
|
||||
detailModel.currentGenre.value == playbackModel.currentGenre.value
|
||||
) {
|
||||
Log.d(this::class.simpleName, "Retard")
|
||||
if (playbackModel.isPlaying.value!!) {
|
||||
binding.genrePlay.setImageResource(R.drawable.ic_pause)
|
||||
} else {
|
||||
binding.genrePlay.setImageResource(R.drawable.ic_play)
|
||||
}
|
||||
|
||||
binding.genrePlay.setOnClickListener {
|
||||
playbackModel.invertPlayingStatus()
|
||||
}
|
||||
} else {
|
||||
binding.genrePlay.setImageResource(R.drawable.ic_play)
|
||||
|
||||
binding.genrePlay.setOnClickListener {
|
||||
playbackModel.play(detailModel.currentGenre.value!!, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ data class Song(
|
|||
data class Album(
|
||||
override val id: Long = -1,
|
||||
override val name: String,
|
||||
val artistName: String,
|
||||
val artistId: Long = -1,
|
||||
val coverUri: Uri = Uri.EMPTY,
|
||||
val year: Int = 0
|
||||
) : BaseModel() {
|
||||
|
@ -52,8 +52,7 @@ data class Album(
|
|||
// Artist
|
||||
data class Artist(
|
||||
override val id: Long = -1,
|
||||
override var name: String,
|
||||
val givenGenres: MutableList<Genre> = mutableListOf()
|
||||
override var name: String
|
||||
) : BaseModel() {
|
||||
val albums = mutableListOf<Album>()
|
||||
val genres = mutableListOf<Genre>()
|
||||
|
@ -75,14 +74,6 @@ data class Artist(
|
|||
}
|
||||
return songs
|
||||
}
|
||||
val genreSongs: MutableList<Song>
|
||||
get() {
|
||||
val songs = mutableListOf<Song>()
|
||||
genres.forEach {
|
||||
songs.addAll(it.songs)
|
||||
}
|
||||
return songs
|
||||
}
|
||||
}
|
||||
|
||||
// Genre
|
||||
|
@ -109,14 +100,6 @@ data class Genre(
|
|||
}
|
||||
return num
|
||||
}
|
||||
val songs: MutableList<Song>
|
||||
get() {
|
||||
val songs = mutableListOf<Song>()
|
||||
artists.forEach {
|
||||
songs.addAll(it.songs)
|
||||
}
|
||||
return songs
|
||||
}
|
||||
}
|
||||
|
||||
// Header [Used for search, nothing else]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.oxycblt.auxio.music.processing
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.Albums
|
||||
import android.provider.MediaStore.Audio.Artists
|
||||
import android.provider.MediaStore.Audio.Genres
|
||||
|
@ -32,11 +32,6 @@ class MusicLoader(
|
|||
var albums = mutableListOf<Album>()
|
||||
var songs = mutableListOf<Song>()
|
||||
|
||||
private var genreCursor: Cursor? = null
|
||||
private var artistCursor: Cursor? = null
|
||||
private var albumCursor: Cursor? = null
|
||||
private var songCursor: Cursor? = null
|
||||
|
||||
val response: MusicLoaderResponse
|
||||
|
||||
init {
|
||||
|
@ -67,7 +62,7 @@ class MusicLoader(
|
|||
Log.d(this::class.simpleName, "Starting genre search...")
|
||||
|
||||
// First, get a cursor for every genre in the android system
|
||||
genreCursor = resolver.query(
|
||||
val genreCursor = resolver.query(
|
||||
Genres.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
Genres._ID, // 0
|
||||
|
@ -86,7 +81,7 @@ class MusicLoader(
|
|||
val id = cursor.getLong(idIndex)
|
||||
var name = cursor.getString(nameIndex) ?: genrePlaceholder
|
||||
|
||||
// If a genre is still in an old int-based format [Android formats it as "(INT)"],
|
||||
// If a genre is still in an old int-based format [Android formats it as "(INT)"],mu
|
||||
// convert that to the corresponding ID3 genre.
|
||||
if (name.contains(Regex("[0123456789)]"))) {
|
||||
name = name.toNamedGenre() ?: genrePlaceholder
|
||||
|
@ -111,42 +106,59 @@ class MusicLoader(
|
|||
private fun loadArtists() {
|
||||
Log.d(this::class.simpleName, "Starting artist search...")
|
||||
|
||||
// Iterate through the artists for each loaded genre, and then add the genre
|
||||
// with the artist.
|
||||
// This is only done because using GENRE_NAME for songs is broken and has been for years.
|
||||
// Load all the artists
|
||||
val artistCursor = resolver.query(
|
||||
Artists.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
Artists._ID, // 0
|
||||
Artists.ARTIST // 1
|
||||
),
|
||||
null, null,
|
||||
Artists.DEFAULT_SORT_ORDER
|
||||
)
|
||||
|
||||
artistCursor?.use { cursor ->
|
||||
val idIndex = cursor.getColumnIndexOrThrow(Artists._ID)
|
||||
val nameIndex = cursor.getColumnIndexOrThrow(Artists.ARTIST)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(idIndex)
|
||||
var name = cursor.getString(nameIndex)
|
||||
|
||||
if (name == null || name == MediaStore.UNKNOWN_STRING) {
|
||||
name = artistPlaceholder
|
||||
}
|
||||
|
||||
Log.d(this::class.simpleName, id.toString())
|
||||
|
||||
artists.add(
|
||||
Artist(
|
||||
id, name
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cursor.close()
|
||||
}
|
||||
|
||||
// Then try to associate any genres with their respective artists.
|
||||
for (genre in genres) {
|
||||
artistCursor = resolver.query(
|
||||
val artistGenreCursor = resolver.query(
|
||||
Genres.Members.getContentUri("external", genre.id),
|
||||
arrayOf(
|
||||
Artists._ID, // 0
|
||||
Artists.ARTIST // 1
|
||||
Genres.Members.ARTIST_ID
|
||||
),
|
||||
null, null,
|
||||
Artists.DEFAULT_SORT_ORDER
|
||||
null, null, null
|
||||
)
|
||||
|
||||
artistCursor?.use { cursor ->
|
||||
val idIndex = cursor.getColumnIndexOrThrow(Artists._ID)
|
||||
val nameIndex = cursor.getColumnIndexOrThrow(Artists.ARTIST)
|
||||
artistGenreCursor?.let { cursor ->
|
||||
val idIndex = cursor.getColumnIndexOrThrow(Genres.Members.ARTIST_ID)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(idIndex)
|
||||
val name = cursor.getString(nameIndex) ?: artistPlaceholder
|
||||
|
||||
// If an artist has already been added [Which is very likely due to how genres
|
||||
// are processed], add the genre to the existing artist instead of creating a
|
||||
// new one.
|
||||
val existingArtist = artists.find { it.name == name }
|
||||
|
||||
if (existingArtist != null) {
|
||||
existingArtist.givenGenres.add(genre)
|
||||
} else {
|
||||
artists.add(
|
||||
Artist(
|
||||
id, name,
|
||||
mutableListOf(genre)
|
||||
)
|
||||
)
|
||||
artists.filter { it.id == id }.forEach {
|
||||
it.genres.add(genre)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,9 +166,8 @@ class MusicLoader(
|
|||
}
|
||||
}
|
||||
|
||||
// Remove dupes [Just in case]
|
||||
artists = artists.distinctBy {
|
||||
it.name to it.givenGenres
|
||||
it.name to it.genres
|
||||
}.toMutableList()
|
||||
|
||||
Log.d(
|
||||
|
@ -168,12 +179,12 @@ class MusicLoader(
|
|||
private fun loadAlbums() {
|
||||
Log.d(this::class.simpleName, "Starting album search...")
|
||||
|
||||
albumCursor = resolver.query(
|
||||
val albumCursor = resolver.query(
|
||||
Albums.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
Albums._ID, // 0
|
||||
Albums.ALBUM, // 1
|
||||
Albums.ARTIST, // 2
|
||||
Albums.ARTIST_ID, // 2
|
||||
|
||||
Albums.FIRST_YEAR, // 3
|
||||
),
|
||||
|
@ -184,20 +195,20 @@ class MusicLoader(
|
|||
albumCursor?.use { cursor ->
|
||||
val idIndex = cursor.getColumnIndexOrThrow(Albums._ID)
|
||||
val nameIndex = cursor.getColumnIndexOrThrow(Albums.ALBUM)
|
||||
val artistIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST)
|
||||
val artistIdIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST_ID)
|
||||
val yearIndex = cursor.getColumnIndexOrThrow(Albums.FIRST_YEAR)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(idIndex)
|
||||
val name = cursor.getString(nameIndex) ?: albumPlaceholder
|
||||
val artist = cursor.getString(artistIndex) ?: artistPlaceholder
|
||||
val artistId = cursor.getLong(artistIdIndex)
|
||||
val year = cursor.getInt(yearIndex)
|
||||
|
||||
val coverUri = id.toAlbumArtURI()
|
||||
|
||||
albums.add(
|
||||
Album(
|
||||
id, name, artist,
|
||||
id, name, artistId,
|
||||
coverUri, year
|
||||
)
|
||||
)
|
||||
|
@ -206,9 +217,8 @@ class MusicLoader(
|
|||
cursor.close()
|
||||
}
|
||||
|
||||
// Remove dupes
|
||||
albums = albums.distinctBy {
|
||||
it.name to it.artistName to it.year to it.numSongs
|
||||
it.name to it.artistId to it.year to it.numSongs
|
||||
}.toMutableList()
|
||||
|
||||
Log.d(
|
||||
|
@ -220,7 +230,7 @@ class MusicLoader(
|
|||
private fun loadSongs() {
|
||||
Log.d(this::class.simpleName, "Starting song search...")
|
||||
|
||||
songCursor = resolver.query(
|
||||
val songCursor = resolver.query(
|
||||
Media.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
Media._ID, // 0
|
||||
|
@ -260,7 +270,6 @@ class MusicLoader(
|
|||
cursor.close()
|
||||
}
|
||||
|
||||
// Remove dupes
|
||||
songs = songs.distinctBy {
|
||||
it.name to it.albumId to it.track to it.duration
|
||||
}.toMutableList()
|
||||
|
|
|
@ -51,8 +51,7 @@ class MusicSorter(
|
|||
if (unknownSongs.size > 0) {
|
||||
|
||||
val unknownAlbum = Album(
|
||||
name = albumPlaceholder,
|
||||
artistName = artistPlaceholder
|
||||
name = albumPlaceholder
|
||||
)
|
||||
|
||||
for (song in unknownSongs) {
|
||||
|
@ -76,7 +75,7 @@ class MusicSorter(
|
|||
|
||||
for (artist in artists) {
|
||||
// Find all albums that match the current artist name
|
||||
val artistAlbums = albums.filter { it.artistName == artist.name }
|
||||
val artistAlbums = albums.filter { it.artistId == artist.id }
|
||||
|
||||
// Then add them to the artist, along with refreshing the amount of albums
|
||||
for (album in artistAlbums) {
|
||||
|
@ -85,8 +84,9 @@ class MusicSorter(
|
|||
}
|
||||
|
||||
// Then group the artist's genres and sort them by "Prominence"
|
||||
// A.K.A Who has the most map entries
|
||||
val groupedGenres = artist.givenGenres.groupBy { it.name }
|
||||
// A.K.A Who has the most bugged duplicate genres
|
||||
val groupedGenres = artist.genres.groupBy { it.name }
|
||||
artist.genres.clear()
|
||||
|
||||
groupedGenres.keys.sortedByDescending { key ->
|
||||
groupedGenres[key]?.size
|
||||
|
@ -129,7 +129,7 @@ class MusicSorter(
|
|||
for (genre in genres) {
|
||||
// Find all artists that match the current genre
|
||||
val genreArtists = artists.filter { artist ->
|
||||
artist.givenGenres.any {
|
||||
artist.genres.any {
|
||||
it.name == genre.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ package org.oxycblt.auxio.playback
|
|||
// IN_ARTIST -> Play from the songs of the artist
|
||||
// IN_ALBUM -> Play from the songs of the album
|
||||
enum class PlaybackMode {
|
||||
IN_GENRE, IN_ARTIST, IN_ALBUM, ALL_SONGS;
|
||||
IN_ARTIST, IN_ALBUM, ALL_SONGS;
|
||||
|
||||
// Make a slice of all the values that this ShowMode covers.
|
||||
// ex. SHOW_ARTISTS would return SHOW_ARTISTS, SHOW_ALBUMS, and SHOW_SONGS
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.Transformations
|
|||
import androidx.lifecycle.ViewModel
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.BaseModel
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
|
@ -21,8 +22,8 @@ class PlaybackViewModel : ViewModel() {
|
|||
private val mCurrentSong = MutableLiveData<Song>()
|
||||
val currentSong: LiveData<Song> get() = mCurrentSong
|
||||
|
||||
private val mCurrentGenre = MutableLiveData<Genre>()
|
||||
val currentGenre: LiveData<Genre> get() = mCurrentGenre
|
||||
private val mCurrentParent = MutableLiveData<BaseModel>()
|
||||
val currentParent: LiveData<BaseModel> get() = mCurrentParent
|
||||
|
||||
private val mQueue = MutableLiveData(mutableListOf<Song>())
|
||||
val queue: LiveData<MutableList<Song>> get() = mQueue
|
||||
|
@ -62,19 +63,6 @@ class PlaybackViewModel : ViewModel() {
|
|||
PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList()
|
||||
PlaybackMode.IN_ARTIST -> song.album.artist.songs
|
||||
PlaybackMode.IN_ALBUM -> song.album.songs
|
||||
|
||||
// Warning: Calling update() with a mode of IN_GENRE Will cause Auxio to play
|
||||
// from the artist's most prominent genre instead of the song's genre.
|
||||
// FIXME: This could be fixed by moving genre loading to songs
|
||||
PlaybackMode.IN_GENRE -> {
|
||||
Log.d(
|
||||
this::class.simpleName,
|
||||
"update() was called with IN_GENRES, using " +
|
||||
"most prominent genre instead of the song's genre."
|
||||
)
|
||||
|
||||
song.album.artist.genres[0].songs
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentMode.value = mode
|
||||
|
@ -90,6 +78,7 @@ class PlaybackViewModel : ViewModel() {
|
|||
|
||||
mQueue.value = songs
|
||||
mCurrentIndex.value = 0
|
||||
mCurrentParent.value = album
|
||||
mCurrentMode.value = PlaybackMode.IN_ALBUM
|
||||
}
|
||||
|
||||
|
@ -102,6 +91,7 @@ class PlaybackViewModel : ViewModel() {
|
|||
|
||||
mQueue.value = songs
|
||||
mCurrentIndex.value = 0
|
||||
mCurrentParent.value = artist
|
||||
mCurrentMode.value = PlaybackMode.IN_ARTIST
|
||||
}
|
||||
|
||||
|
@ -112,10 +102,8 @@ class PlaybackViewModel : ViewModel() {
|
|||
|
||||
updatePlayback(songs[0])
|
||||
|
||||
mCurrentGenre.value = genre
|
||||
mQueue.value = songs
|
||||
mCurrentIndex.value = 0
|
||||
mCurrentMode.value = PlaybackMode.IN_GENRE
|
||||
}
|
||||
|
||||
private fun updatePlayback(song: Song) {
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_song_header"
|
||||
tools:itemCount="4"
|
||||
tools:listitem="@layout/item_album_song" />
|
||||
|
|
|
@ -158,6 +158,7 @@
|
|||
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" />
|
||||
|
|
|
@ -99,23 +99,6 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/genre_counts"
|
||||
tools:text="80 Songs" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/genre_play"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/margin_tiny"
|
||||
android:layout_marginEnd="@dimen/margin_medium"
|
||||
android:background="@drawable/ui_circular_button"
|
||||
android:backgroundTint="?android:attr/colorPrimary"
|
||||
android:contentDescription="@string/description_play"
|
||||
android:src="@drawable/ic_play"
|
||||
android:onClick="@{() -> playbackModel.play(genre, false)}"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/genre_song_count"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/genre_counts" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/genre_artist_header"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -159,6 +142,7 @@
|
|||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/genre_artist_header"
|
||||
tools:itemCount="4"
|
||||
tools:listitem="@layout/item_artist" />
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="@dimen/margin_mid_large"
|
||||
android:elevation="4dp"
|
||||
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
||||
app:coverArt="@{song}"
|
||||
app:layout_constraintBottom_toTopOf="@+id/playback_song"
|
||||
|
|
Loading…
Reference in a new issue