Add album detail fragment

Add a fragment for album details.
This commit is contained in:
OxygenCobalt 2020-09-17 14:51:14 -06:00
parent ebc5aac011
commit 20047313fc
11 changed files with 198 additions and 23 deletions

View file

@ -0,0 +1,37 @@
package org.oxycblt.auxio.detail
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.navArgs
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
import org.oxycblt.auxio.music.MusicViewModel
class AlbumDetailFragment : Fragment() {
private val args: AlbumDetailFragmentArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentAlbumDetailBinding.inflate(inflater)
// I honestly don't want to turn of the any data classes into parcelables due to how
// many lists they store, so just pick up the artist id and find it from musicModel.
val musicModel: MusicViewModel by activityViewModels()
val album = musicModel.albums.value?.find { it.id == args.albumId }!!
binding.lifecycleOwner = this
binding.album = album
Log.d(this::class.simpleName, "Fragment created.")
return binding.root
}
}

View file

@ -7,14 +7,21 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import org.oxycblt.auxio.ClickListener
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
import org.oxycblt.auxio.library.DetailViewModel
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.theme.applyDivider
class ArtistDetailFragment : Fragment() {
private val args: ArtistDetailFragmentArgs by navArgs()
private val detailModel: DetailViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -22,12 +29,10 @@ class ArtistDetailFragment : Fragment() {
): View? {
val binding = FragmentArtistDetailBinding.inflate(inflater)
// I honestly don't want to turn of the any data classes into a parcelables due to how
// I honestly don't want to turn of the any data classes into parcelables due to how
// many lists they store, so just pick up the artist id and find it from musicModel.
val musicModel: MusicViewModel by activityViewModels()
val artistId = ArtistDetailFragmentArgs.fromBundle(requireArguments()).artistId
val artist = musicModel.artists.value?.find { it.id == artistId }!!
val artist = musicModel.artists.value?.find { it.id == args.artistId }!!
binding.lifecycleOwner = this
binding.artist = artist
@ -35,7 +40,7 @@ class ArtistDetailFragment : Fragment() {
binding.albumRecycler.adapter = DetailAlbumAdapter(
artist.albums,
ClickListener {
Log.d(this::class.simpleName, it.name)
navToAlbum(it)
}
)
binding.albumRecycler.applyDivider()
@ -45,4 +50,21 @@ class ArtistDetailFragment : Fragment() {
return binding.root
}
override fun onResume() {
super.onResume()
detailModel.isAlreadyNavigating = false
}
private fun navToAlbum(album: Album) {
// Don't navigate if an item already has been selected.
if (!detailModel.isAlreadyNavigating) {
detailModel.isAlreadyNavigating = true
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(album.id)
)
}
}
}

View file

@ -0,0 +1,7 @@
package org.oxycblt.auxio.library
import androidx.lifecycle.ViewModel
class DetailViewModel : ViewModel() {
var isAlreadyNavigating = false
}

View file

@ -50,11 +50,10 @@ class LibraryFragment : Fragment() {
}
private fun navToArtist(artist: Artist) {
// Don't navigate if an item already has been selected.
if (!libraryModel.isAlreadyNavigating) {
libraryModel.isAlreadyNavigating = true
// When navigation, pass the artistImage of the item as a shared element to create
// the image popup.
findNavController().navigate(
MainFragmentDirections.actionShowArtist(artist.id)
)

View file

@ -82,17 +82,8 @@ fun TextView.bindArtistCounts(artist: Artist) {
text = context.getString(R.string.format_double_counts, albums, songs)
}
// TODO: Add option to just list all genres.
@BindingAdapter("artistGenre")
fun TextView.getArtistGenre(artist: Artist) {
// If the artist has more than one genre, pick the most used one.
// TODO: Add an option to display all genres.
val genre: String = if (artist.genres.size > 1) {
val genres = artist.genres.groupBy { it.name }
genres.keys.sortedByDescending { genres[it]?.size }[0]
} else {
artist.genres[0].name
}
text = genre
text = artist.genre
}

View file

@ -8,7 +8,7 @@ data class Album(
var name: String = "",
val artistName: String = "", // only used for sorting. Use artist.name instead.
val coverUri: Uri = Uri.EMPTY,
val year: Int = 0
val year: String = ""
) {
lateinit var artist: Artist

View file

@ -7,6 +7,7 @@ data class Artist(
val genres: MutableList<Genre> = mutableListOf(Genre())
) {
val albums = mutableListOf<Album>()
var genre = ""
val numAlbums: Int get() = albums.size
var numSongs = 0
@ -17,5 +18,14 @@ data class Artist(
albums.forEach { album ->
numSongs += album.numSongs
}
// If the artist has more than one genre, pick the most used one.
genre = if (genres.size > 1) {
val groupGenres = genres.groupBy { it.name }
groupGenres.keys.sortedByDescending { groupGenres[it]?.size }[0]
} else {
genres[0].name
}
}
}

View file

@ -191,7 +191,7 @@ class MusicLoader(private val resolver: ContentResolver) {
albums.add(
Album(
id, name, artist,
coverUri, year
coverUri, year.toString()
)
)
}

View file

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="album"
type="org.oxycblt.auxio.music.models.Album" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
app:title="@string/title_library_fragment"
tools:titleTextColor="@color/blue" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical">
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/cover_size_huge"
android:layout_height="@dimen/cover_size_huge"
android:layout_marginTop="@dimen/margin_medium"
app:coverArt="@{album}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/artist_name"
style="@style/DetailHeader"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginEnd="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_medium"
android:text="@{album.name}"
app:autoSizeMaxTextSize="@dimen/detail_header_size_max"
app:autoSizeMinTextSize="@dimen/detail_header_size_min"
app:autoSizeStepGranularity="@dimen/detail_header_size_increment"
app:autoSizeTextType="uniform"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cover"
tools:text="Album Name" />
<TextView
android:id="@+id/album_year"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginStart="@dimen/margin_medium"
android:text="@{album.year}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_name"
tools:text="2020" />
<TextView
android:id="@+id/artist_counts"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginStart="@dimen/margin_medium"
app:songCount="@{album}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_year"
tools:text="20 Songs" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</layout>

View file

@ -38,5 +38,21 @@
<argument
android:name="artistId"
app:argType="long" />
<action
android:id="@+id/action_show_album"
app:enterAnim="@anim/fragment_fade_enter"
app:exitAnim="@anim/fragment_fade_exit"
app:popEnterAnim="@anim/fragment_fade_enter"
app:popExitAnim="@anim/fragment_fade_exit"
app:destination="@id/album_detail_fragment" />
</fragment>
<fragment
android:id="@+id/album_detail_fragment"
android:name="org.oxycblt.auxio.detail.AlbumDetailFragment"
android:label="AlbumDetailFragment"
tools:layout="@layout/fragment_album_detail">
<argument
android:name="albumId"
app:argType="long" />
</fragment>
</navigation>

View file

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<fade xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime" />