Add RecyclerView to LibraryFragment
Add a basic RecyclerView to LibraryFragment that shows every album.
This commit is contained in:
parent
37b071de0d
commit
c04a90c3fa
8 changed files with 126 additions and 20 deletions
|
@ -7,9 +7,11 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
|
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
|
||||||
|
import org.oxycblt.auxio.library.recycler.AlbumDataAdapter
|
||||||
import org.oxycblt.auxio.music.MusicRepository
|
import org.oxycblt.auxio.music.MusicRepository
|
||||||
|
|
||||||
class LibraryFragment : Fragment() {
|
class LibraryFragment : Fragment() {
|
||||||
|
@ -27,11 +29,16 @@ class LibraryFragment : Fragment() {
|
||||||
inflater, R.layout.fragment_library, container, false
|
inflater, R.layout.fragment_library, container, false
|
||||||
)
|
)
|
||||||
|
|
||||||
libraryModel
|
val adapter = AlbumDataAdapter()
|
||||||
|
binding.libraryRecycler.adapter = adapter
|
||||||
|
|
||||||
val albums = MusicRepository.getInstance().albums.value
|
val repo = MusicRepository.getInstance()
|
||||||
|
repo.albums.observe(
|
||||||
binding.testAlbum.setImageBitmap(albums?.get((0..albums.size).random())?.cover)
|
viewLifecycleOwner,
|
||||||
|
Observer {
|
||||||
|
adapter.data = it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Log.d(this::class.simpleName, "Fragment created.")
|
Log.d(this::class.simpleName, "Fragment created.")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.oxycblt.auxio.library.recycler
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import org.oxycblt.auxio.databinding.LibraryItemBinding
|
||||||
|
import org.oxycblt.auxio.music.models.Album
|
||||||
|
|
||||||
|
class AlbumDataAdapter : ListAdapter<Album, LibraryViewHolder>(DiffCallback) {
|
||||||
|
|
||||||
|
var data = listOf<Album>()
|
||||||
|
set(newData) {
|
||||||
|
field = newData
|
||||||
|
submitList(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LibraryViewHolder {
|
||||||
|
return LibraryViewHolder(
|
||||||
|
LibraryItemBinding.inflate(LayoutInflater.from(parent.context))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: LibraryViewHolder, position: Int) {
|
||||||
|
val album = getItem(position)
|
||||||
|
|
||||||
|
holder.bindAlbum(album)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object DiffCallback : DiffUtil.ItemCallback<Album>() {
|
||||||
|
override fun areItemsTheSame(oldItem: Album, newItem: Album): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: Album, newItem: Album): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.oxycblt.auxio.library.recycler
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.databinding.LibraryItemBinding
|
||||||
|
import org.oxycblt.auxio.music.models.Album
|
||||||
|
import org.oxycblt.auxio.music.models.Artist
|
||||||
|
|
||||||
|
class LibraryViewHolder(
|
||||||
|
private var binding: LibraryItemBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
// Bind the view w/new data
|
||||||
|
fun bindAlbum(album: Album) {
|
||||||
|
binding.album = album
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bindArtist(artist: Artist) {
|
||||||
|
// TODO: Not implemented.
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,9 +32,9 @@ private val ID3_GENRES = arrayOf<String>(
|
||||||
const val PAREN_FILTER = "()"
|
const val PAREN_FILTER = "()"
|
||||||
|
|
||||||
// Convert legacy ID3 genres to a named genre
|
// Convert legacy ID3 genres to a named genre
|
||||||
fun intToNamedGenre(genre: String): String {
|
fun String.toNamedGenre(): String {
|
||||||
// Strip the genres of any parentheses, and convert it to an int
|
// Strip the genres of any parentheses, and convert it to an int
|
||||||
val intGenre = genre.filterNot {
|
val intGenre = this.filterNot {
|
||||||
PAREN_FILTER.indexOf(it) > -1
|
PAREN_FILTER.indexOf(it) > -1
|
||||||
}.toInt()
|
}.toInt()
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,13 @@ import android.provider.MediaStore.Audio.Artists
|
||||||
import android.provider.MediaStore.Audio.Genres
|
import android.provider.MediaStore.Audio.Genres
|
||||||
import android.provider.MediaStore.Audio.Media
|
import android.provider.MediaStore.Audio.Media
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.oxycblt.auxio.music.intToNamedGenre
|
|
||||||
import org.oxycblt.auxio.music.models.Album
|
import org.oxycblt.auxio.music.models.Album
|
||||||
import org.oxycblt.auxio.music.models.Artist
|
import org.oxycblt.auxio.music.models.Artist
|
||||||
import org.oxycblt.auxio.music.models.Genre
|
import org.oxycblt.auxio.music.models.Genre
|
||||||
import org.oxycblt.auxio.music.models.Song
|
import org.oxycblt.auxio.music.models.Song
|
||||||
import org.oxycblt.auxio.music.toAlbumArtURI
|
import org.oxycblt.auxio.music.toAlbumArtURI
|
||||||
|
import org.oxycblt.auxio.music.toNamedGenre
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
enum class MusicLoaderResponse {
|
enum class MusicLoaderResponse {
|
||||||
DONE, FAILURE, NO_MUSIC
|
DONE, FAILURE, NO_MUSIC
|
||||||
|
@ -87,7 +88,7 @@ class MusicLoader(private val app: Application) {
|
||||||
// convert that to the corresponding ID3 genre. Really hope anyone doesn't have
|
// convert that to the corresponding ID3 genre. Really hope anyone doesn't have
|
||||||
// a genre that contains parentheses.
|
// a genre that contains parentheses.
|
||||||
if (name.contains(Regex("[()]"))) {
|
if (name.contains(Regex("[()]"))) {
|
||||||
name = intToNamedGenre(name)
|
name = name.toNamedGenre()
|
||||||
}
|
}
|
||||||
|
|
||||||
genres.add(
|
genres.add(
|
||||||
|
@ -193,17 +194,24 @@ class MusicLoader(private val app: Application) {
|
||||||
val year = cursor.getInt(yearIndex)
|
val year = cursor.getInt(yearIndex)
|
||||||
val numSongs = cursor.getInt(numIndex)
|
val numSongs = cursor.getInt(numIndex)
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// Album art loading during the initial load isn't really practical for a large amount of albums
|
||||||
|
// Use glide or something
|
||||||
val artUri = id.toAlbumArtURI()
|
val artUri = id.toAlbumArtURI()
|
||||||
var cover: Bitmap? = null
|
var cover: Bitmap? = null
|
||||||
|
|
||||||
// Get the album art through either ImageDecoder or MediaStore depending on the
|
// Get the album art through either ImageDecoder or MediaStore depending on the
|
||||||
// version.
|
// version.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
try {
|
||||||
cover = ImageDecoder.decodeBitmap(
|
cover = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
ImageDecoder.createSource(resolver, artUri)
|
ImageDecoder.decodeBitmap(
|
||||||
)
|
ImageDecoder.createSource(resolver, artUri)
|
||||||
} else {
|
)
|
||||||
cover = MediaStore.Images.Media.getBitmap(resolver, artUri)
|
} else {
|
||||||
|
MediaStore.Images.Media.getBitmap(resolver, artUri)
|
||||||
|
}
|
||||||
|
} catch (noFound: FileNotFoundException) {
|
||||||
|
cover = null
|
||||||
}
|
}
|
||||||
|
|
||||||
albums.add(
|
albums.add(
|
||||||
|
|
|
@ -17,14 +17,15 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:title="@string/title_library_fragment" />
|
app:title="@string/title_library_fragment" />
|
||||||
|
|
||||||
<ImageView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/testAlbum"
|
android:id="@+id/library_recycler"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</layout>
|
</layout>
|
28
app/src/main/res/layout/library_item.xml
Normal file
28
app/src/main/res/layout/library_item.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="album"
|
||||||
|
type="org.oxycblt.auxio.music.models.Album" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/albumNameText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{album.title}"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Album Name" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</layout>
|
|
@ -12,7 +12,9 @@
|
||||||
tools:layout="@layout/fragment_loading">
|
tools:layout="@layout/fragment_loading">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_to_library"
|
android:id="@+id/action_to_library"
|
||||||
app:destination="@id/libraryFragment" />
|
app:destination="@id/libraryFragment"
|
||||||
|
app:popUpTo="@id/loadingFragment"
|
||||||
|
app:popUpToInclusive="true" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/libraryFragment"
|
android:id="@+id/libraryFragment"
|
||||||
|
|
Loading…
Reference in a new issue