diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index b67662d9d..ef7ad7567 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -7,9 +7,11 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentLibraryBinding +import org.oxycblt.auxio.library.recycler.AlbumDataAdapter import org.oxycblt.auxio.music.MusicRepository class LibraryFragment : Fragment() { @@ -27,11 +29,16 @@ class LibraryFragment : Fragment() { inflater, R.layout.fragment_library, container, false ) - libraryModel + val adapter = AlbumDataAdapter() + binding.libraryRecycler.adapter = adapter - val albums = MusicRepository.getInstance().albums.value - - binding.testAlbum.setImageBitmap(albums?.get((0..albums.size).random())?.cover) + val repo = MusicRepository.getInstance() + repo.albums.observe( + viewLifecycleOwner, + Observer { + adapter.data = it + } + ) Log.d(this::class.simpleName, "Fragment created.") diff --git a/app/src/main/java/org/oxycblt/auxio/library/recycler/AlbumDataAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/recycler/AlbumDataAdapter.kt new file mode 100644 index 000000000..a90929a8d --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/library/recycler/AlbumDataAdapter.kt @@ -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(DiffCallback) { + + var data = listOf() + 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() { + override fun areItemsTheSame(oldItem: Album, newItem: Album): Boolean { + return oldItem == newItem + } + + override fun areContentsTheSame(oldItem: Album, newItem: Album): Boolean { + return oldItem.id == newItem.id + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryViewHolder.kt b/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryViewHolder.kt new file mode 100644 index 000000000..fbce64d3a --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/library/recycler/LibraryViewHolder.kt @@ -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. + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt index e5c625c52..4460345ae 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -32,9 +32,9 @@ private val ID3_GENRES = arrayOf( const val PAREN_FILTER = "()" // 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 - val intGenre = genre.filterNot { + val intGenre = this.filterNot { PAREN_FILTER.indexOf(it) > -1 }.toInt() diff --git a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt index 7e8238acb..7865da7f0 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt @@ -12,12 +12,13 @@ import android.provider.MediaStore.Audio.Artists import android.provider.MediaStore.Audio.Genres import android.provider.MediaStore.Audio.Media import android.util.Log -import org.oxycblt.auxio.music.intToNamedGenre import org.oxycblt.auxio.music.models.Album import org.oxycblt.auxio.music.models.Artist import org.oxycblt.auxio.music.models.Genre import org.oxycblt.auxio.music.models.Song import org.oxycblt.auxio.music.toAlbumArtURI +import org.oxycblt.auxio.music.toNamedGenre +import java.io.FileNotFoundException enum class MusicLoaderResponse { 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 // a genre that contains parentheses. if (name.contains(Regex("[()]"))) { - name = intToNamedGenre(name) + name = name.toNamedGenre() } genres.add( @@ -193,17 +194,24 @@ class MusicLoader(private val app: Application) { val year = cursor.getInt(yearIndex) 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() var cover: Bitmap? = null // Get the album art through either ImageDecoder or MediaStore depending on the // version. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - cover = ImageDecoder.decodeBitmap( - ImageDecoder.createSource(resolver, artUri) - ) - } else { - cover = MediaStore.Images.Media.getBitmap(resolver, artUri) + try { + cover = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ImageDecoder.decodeBitmap( + ImageDecoder.createSource(resolver, artUri) + ) + } else { + MediaStore.Images.Media.getBitmap(resolver, artUri) + } + } catch (noFound: FileNotFoundException) { + cover = null } albums.add( diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 1a3b83d8f..7c5469cee 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -17,14 +17,15 @@ app:layout_constraintTop_toTopOf="parent" app:title="@string/title_library_fragment" /> - + app:layout_constraintTop_toBottomOf="@+id/toolbar" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> \ No newline at end of file diff --git a/app/src/main/res/layout/library_item.xml b/app/src/main/res/layout/library_item.xml new file mode 100644 index 000000000..871d4d06b --- /dev/null +++ b/app/src/main/res/layout/library_item.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_main.xml b/app/src/main/res/navigation/nav_main.xml index 409c819c0..7cca06381 100644 --- a/app/src/main/res/navigation/nav_main.xml +++ b/app/src/main/res/navigation/nav_main.xml @@ -12,7 +12,9 @@ tools:layout="@layout/fragment_loading"> + app:destination="@id/libraryFragment" + app:popUpTo="@id/loadingFragment" + app:popUpToInclusive="true" />