Update album items/details

Update the ArtistDetailFragment album item to show the year instead of song count. Update AlbumDetailFragment to show year, song count, and total duration.
This commit is contained in:
OxygenCobalt 2020-09-26 13:57:15 -06:00
parent f754a82ba7
commit 5191220bc0
13 changed files with 123 additions and 191 deletions

View file

@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemAlbumBinding import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.music.models.Album import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.recycler.AlbumDiffCallback import org.oxycblt.auxio.recycler.AlbumDiffCallback
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
@ -15,7 +15,7 @@ class DetailAlbumAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder( return ViewHolder(
ItemAlbumBinding.inflate(LayoutInflater.from(parent.context)) ItemArtistAlbumBinding.inflate(LayoutInflater.from(parent.context))
) )
} }
@ -25,7 +25,7 @@ class DetailAlbumAdapter(
// Generic ViewHolder for an album // Generic ViewHolder for an album
inner class ViewHolder( inner class ViewHolder(
private val binding: ItemAlbumBinding private val binding: ItemArtistAlbumBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
init { init {

View file

@ -1,8 +1,10 @@
package org.oxycblt.auxio.music package org.oxycblt.auxio.music
import android.content.ContentUris import android.content.ContentUris
import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.MediaStore import android.provider.MediaStore
import android.text.format.DateUtils
import android.widget.TextView import android.widget.TextView
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -68,15 +70,17 @@ fun Long.toAlbumArtURI(): Uri {
) )
} }
// Cut off excess zeros from a duration string // Convert a string into its duration
fun String.removeDurationZeroes(): String { fun Long.toDuration(): String {
val split = this.chunked(1).toMutableList() val durationString = DateUtils.formatElapsedTime(this)
val durationSplit = durationString.chunked(1).toMutableList()
// Iterate through the string and remove the first zero found // Iterate through the string and remove the first zero found
// If anything else is found, exit the loop. // If anything else is found, exit the loop.
for (i in 0 until length) { for (i in 0 until durationSplit.size) {
if (this[i] == '0') { if (durationSplit[i] == "0") {
split.removeAt(i) durationSplit.removeAt(i)
break break
} else { } else {
@ -84,19 +88,23 @@ fun String.removeDurationZeroes(): String {
} }
} }
return split.joinToString("") return durationSplit.joinToString("")
} }
// --- BINDING ADAPTERS --- // --- BINDING ADAPTERS ---
// Format the amount of songs in an album fun getAlbumSongCount(album: Album, context: Context): String {
@BindingAdapter("songCount") return context.resources.getQuantityString(
fun TextView.getAlbumSongs(album: Album) {
text = context.resources.getQuantityString(
R.plurals.format_song_count, album.numSongs, album.numSongs R.plurals.format_song_count, album.numSongs, album.numSongs
) )
} }
// Format the amount of songs in an album
@BindingAdapter("songCount")
fun TextView.bindAlbumSongs(album: Album) {
text = getAlbumSongCount(album, context)
}
@BindingAdapter("artistCounts") @BindingAdapter("artistCounts")
fun TextView.bindArtistCounts(artist: Artist) { fun TextView.bindArtistCounts(artist: Artist) {
val albums = context.resources.getQuantityString( val albums = context.resources.getQuantityString(
@ -112,7 +120,7 @@ fun TextView.bindArtistCounts(artist: Artist) {
// Get the artist genre. // Get the artist genre.
// TODO: Add option to list all genres // TODO: Add option to list all genres
@BindingAdapter("artistGenre") @BindingAdapter("artistGenre")
fun TextView.getArtistGenre(artist: Artist) { fun TextView.bindArtistGenre(artist: Artist) {
// If there are multiple genres, then pick the most "Prominent" one, // If there are multiple genres, then pick the most "Prominent" one,
// Otherwise just pick the first one // Otherwise just pick the first one
if (artist.genres.keys.size > 1) { if (artist.genres.keys.size > 1) {
@ -123,3 +131,14 @@ fun TextView.getArtistGenre(artist: Artist) {
text = artist.genres.keys.first() text = artist.genres.keys.first()
} }
} }
// Get a bunch of miscellaneous album information [Year, Songs, Duration] and combine them
@BindingAdapter("albumDetails")
fun TextView.bindAlbumDetails(album: Album) {
text = context.getString(
R.string.format_double_info,
album.year.toString(),
getAlbumSongCount(album, context),
album.totalDuration
)
}

View file

@ -1,6 +1,7 @@
package org.oxycblt.auxio.music.models package org.oxycblt.auxio.music.models
import android.net.Uri import android.net.Uri
import org.oxycblt.auxio.music.toDuration
// Abstraction for Song // Abstraction for Song
data class Album( data class Album(
@ -14,4 +15,11 @@ data class Album(
val songs = mutableListOf<Song>() val songs = mutableListOf<Song>()
val numSongs: Int get() = songs.size val numSongs: Int get() = songs.size
val totalDuration: String get() {
var seconds: Long = 0
songs.forEach {
seconds += it.seconds
}
return seconds.toDuration()
}
} }

View file

@ -1,7 +1,6 @@
package org.oxycblt.auxio.music.models package org.oxycblt.auxio.music.models
import android.text.format.DateUtils import org.oxycblt.auxio.music.toDuration
import org.oxycblt.auxio.music.removeDurationZeroes
// Class containing all relevant values for a song. // Class containing all relevant values for a song.
data class Song( data class Song(
@ -14,5 +13,5 @@ data class Song(
lateinit var album: Album lateinit var album: Album
val seconds = duration / 1000 val seconds = duration / 1000
val formattedDuration: String = DateUtils.formatElapsedTime(seconds).removeDurationZeroes() val formattedDuration: String = seconds.toDuration()
} }

View file

@ -22,9 +22,9 @@
</aapt:attr> </aapt:attr>
</path> </path>
<path <path
android:fillColor="#FFFFFF" android:fillColor="#0d5af5"
android:fillType="nonZero" android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1" android:strokeWidth="1"
android:strokeColor="#00000000" /> android:strokeColor="#0d5af500" />
</vector> </vector>

View file

@ -5,166 +5,6 @@
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<path <path
android:fillColor="#3DDC84" android:fillColor="#111111"
android:pathData="M0,0h108v108h-108z" /> android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector> </vector>

View file

@ -86,13 +86,14 @@
tools:text="Artist Name" /> tools:text="Artist Name" />
<TextView <TextView
android:id="@+id/album_year" android:id="@+id/album_other_details"
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="@{album.year != 0 ? String.valueOf(album.year) : @string/placeholder_no_date}" android:text="@{album.year != 0 ? String.valueOf(album.year) : @string/placeholder_no_date}"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:albumDetails="@{album}"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_name" app:layout_constraintTop_toBottomOf="@+id/artist_name"
tools:text="2020" /> tools:text="2020" />
@ -111,7 +112,7 @@
android:text="@string/label_songs" android:text="@string/label_songs"
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline" android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@+id/album_year" /> app:layout_constraintTop_toBottomOf="@+id/album_other_details" />
<ImageButton <ImageButton
android:id="@+id/sort_button" android:id="@+id/sort_button"
@ -128,7 +129,7 @@
tools:src="@drawable/ic_sort_numeric_down" tools:src="@drawable/ic_sort_numeric_down"
app:layout_constraintBottom_toTopOf="@+id/song_recycler" app:layout_constraintBottom_toTopOf="@+id/song_recycler"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_year" /> app:layout_constraintTop_toBottomOf="@+id/album_other_details" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/song_recycler" android:id="@+id/song_recycler"

View file

@ -139,7 +139,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/header_title" app:layout_constraintTop_toBottomOf="@+id/header_title"
tools:itemCount="4" tools:itemCount="4"
tools:listitem="@layout/item_album" /> tools:listitem="@layout/item_artist_album" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View file

@ -39,7 +39,7 @@
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
app:layout_constraintBottom_toTopOf="@+id/song_count" app:layout_constraintBottom_toTopOf="@+id/album_other_details"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/cover" app:layout_constraintStart_toEndOf="@+id/cover"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
@ -47,12 +47,13 @@
tools:text="Album Name" /> tools:text="Album Name" />
<TextView <TextView
android:id="@+id/song_count" android:id="@+id/album_other_details"
android:layout_width="wrap_content" android:layout_width="wrap_content"
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/textAppearanceListItemSecondary" android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/cover" app:layout_constraintStart_toEndOf="@+id/cover"
app:layout_constraintTop_toBottomOf="@+id/album_name" app:layout_constraintTop_toBottomOf="@+id/album_name"

View file

@ -0,0 +1,63 @@
<?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="wrap_content"
android:background="@drawable/ripple"
android:clickable="true"
android:focusable="true"
android:padding="@dimen/padding_medium">
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/cover_size_normal"
android:layout_height="@dimen/cover_size_normal"
android:contentDescription="@{@string/description_album_cover(album.name)}"
app:coverArt="@{album}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<TextView
android:id="@+id/album_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_medium"
android:text="@{album.name}"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toTopOf="@+id/album_other_details"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Album Name" />
<TextView
android:id="@+id/album_other_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_medium"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/cover"
app:layout_constraintTop_toBottomOf="@+id/album_name"
android:text="@{String.valueOf(album.year)}"
tools:text="2020" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -67,11 +67,11 @@
<TextView <TextView
android:id="@+id/duration" android:id="@+id/duration"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="end"
android:text="@{song.formattedDuration}" android:text="@{song.formattedDuration}"
android:textAlignment="center" android:textAlignment="viewEnd"
android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorTertiary" android:textColor="?android:attr/textColorTertiary"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View file

@ -13,7 +13,7 @@
<dimen name="cover_size_compact">44dp</dimen> <dimen name="cover_size_compact">44dp</dimen>
<dimen name="cover_size_normal">56dp</dimen> <dimen name="cover_size_normal">56dp</dimen>
<dimen name="cover_size_large">80dp</dimen> <dimen name="cover_size_large">68dp</dimen>
<dimen name="cover_size_huge">230dp</dimen> <dimen name="cover_size_huge">230dp</dimen>
<dimen name="track_number_width">32dp</dimen> <dimen name="track_number_width">32dp</dimen>

View file

@ -26,6 +26,7 @@
<string name="placeholder_no_date">No Date</string> <string name="placeholder_no_date">No Date</string>
<string name="format_info">%1$s / %2$s</string> <string name="format_info">%1$s / %2$s</string>
<string name="format_double_info">%1$s / %2$s / %3$s</string>
<string name="format_double_counts">%1$s, %2$s</string> <string name="format_double_counts">%1$s, %2$s</string>
<plurals name="format_song_count"> <plurals name="format_song_count">