detail: improve disc header design
This commit is contained in:
parent
190abd5588
commit
97faa3f20e
4 changed files with 78 additions and 30 deletions
|
@ -49,8 +49,10 @@ object IntegerTable {
|
|||
const val VIEW_TYPE_ARTIST_SONG = 0xA00A
|
||||
/** DiscHeaderViewHolder */
|
||||
const val VIEW_TYPE_DISC_HEADER = 0xA00B
|
||||
/** DiscHeaderViewHolder */
|
||||
const val VIEW_TYPE_DISC_DIVIDER = 0xA00C
|
||||
/** EditHeaderViewHolder */
|
||||
const val VIEW_TYPE_EDIT_HEADER = 0xA00C
|
||||
const val VIEW_TYPE_EDIT_HEADER = 0xA00D
|
||||
/** PlaylistSongViewHolder */
|
||||
const val VIEW_TYPE_PLAYLIST_SONG = 0xA00E
|
||||
/** "Music playback" notification code */
|
||||
|
|
|
@ -29,6 +29,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.yield
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.detail.list.DiscDivider
|
||||
import org.oxycblt.auxio.detail.list.DiscHeader
|
||||
import org.oxycblt.auxio.detail.list.EditHeader
|
||||
import org.oxycblt.auxio.detail.list.SortHeader
|
||||
|
@ -554,7 +555,16 @@ constructor(
|
|||
newList.add(Divider(header))
|
||||
}
|
||||
newList.add(header)
|
||||
section.discs.flatMap { listOf(DiscHeader(it.key)) + it.value }
|
||||
buildList<Item> {
|
||||
for (entry in section.discs) {
|
||||
val discHeader = DiscHeader(inner = entry.key)
|
||||
if (isNotEmpty()) {
|
||||
add(DiscDivider(discHeader))
|
||||
}
|
||||
add(discHeader)
|
||||
addAll(entry.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Currently only the final section (songs, which can be sorted) are invalidatable
|
||||
|
|
|
@ -24,6 +24,7 @@ import androidx.core.view.isGone
|
|||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.divider.MaterialDivider
|
||||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
|
||||
|
@ -38,6 +39,7 @@ import org.oxycblt.auxio.music.info.Disc
|
|||
import org.oxycblt.auxio.music.info.resolveNumber
|
||||
import org.oxycblt.auxio.playback.formatDurationMs
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
|
||||
/**
|
||||
|
@ -52,6 +54,7 @@ class AlbumDetailListAdapter(private val listener: Listener<Song>) :
|
|||
when (getItem(position)) {
|
||||
// Support sub-headers for each disc, and special album songs.
|
||||
is DiscHeader -> DiscHeaderViewHolder.VIEW_TYPE
|
||||
is DiscDivider -> DiscDividerViewHolder.VIEW_TYPE
|
||||
is Song -> AlbumSongViewHolder.VIEW_TYPE
|
||||
else -> super.getItemViewType(position)
|
||||
}
|
||||
|
@ -59,6 +62,7 @@ class AlbumDetailListAdapter(private val listener: Listener<Song>) :
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
when (viewType) {
|
||||
DiscHeaderViewHolder.VIEW_TYPE -> DiscHeaderViewHolder.from(parent)
|
||||
DiscDividerViewHolder.VIEW_TYPE -> DiscDividerViewHolder.from(parent)
|
||||
AlbumSongViewHolder.VIEW_TYPE -> AlbumSongViewHolder.from(parent)
|
||||
else -> super.onCreateViewHolder(parent, viewType)
|
||||
}
|
||||
|
@ -79,6 +83,8 @@ class AlbumDetailListAdapter(private val listener: Listener<Song>) :
|
|||
when {
|
||||
oldItem is Disc && newItem is Disc ->
|
||||
DiscHeaderViewHolder.DIFF_CALLBACK.areContentsTheSame(oldItem, newItem)
|
||||
oldItem is DiscDivider && newItem is DiscDivider ->
|
||||
DiscDividerViewHolder.DIFF_CALLBACK.areContentsTheSame(oldItem, newItem)
|
||||
oldItem is Song && newItem is Song ->
|
||||
AlbumSongViewHolder.DIFF_CALLBACK.areContentsTheSame(oldItem, newItem)
|
||||
|
||||
|
@ -96,6 +102,8 @@ class AlbumDetailListAdapter(private val listener: Listener<Song>) :
|
|||
*/
|
||||
data class DiscHeader(val inner: Disc?) : Item
|
||||
|
||||
data class DiscDivider(val anchor: DiscHeader?) : Item
|
||||
|
||||
/**
|
||||
* A [RecyclerView.ViewHolder] that displays a [DiscHeader] to delimit different disc groups. Use
|
||||
* [from] to create an instance.
|
||||
|
@ -140,6 +148,42 @@ private class DiscHeaderViewHolder(private val binding: ItemDiscHeaderBinding) :
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [RecyclerView.ViewHolder] that displays a [DiscHeader]. Use [from] to create an instance.
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class DiscDividerViewHolder private constructor(divider: MaterialDivider) :
|
||||
RecyclerView.ViewHolder(divider) {
|
||||
|
||||
init {
|
||||
divider.dividerColor =
|
||||
divider.context
|
||||
.getAttrColorCompat(com.google.android.material.R.attr.colorOutlineVariant)
|
||||
.defaultColor
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** Unique ID for this ViewHolder type. */
|
||||
const val VIEW_TYPE = IntegerTable.VIEW_TYPE_DISC_DIVIDER
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param parent The parent to inflate this instance from.
|
||||
* @return A new instance.
|
||||
*/
|
||||
fun from(parent: View) = DiscDividerViewHolder(MaterialDivider(parent.context))
|
||||
|
||||
/** A comparator that can be used with DiffUtil. */
|
||||
val DIFF_CALLBACK =
|
||||
object : SimpleDiffCallback<DiscDivider>() {
|
||||
override fun areContentsTheSame(oldItem: DiscDivider, newItem: DiscDivider) =
|
||||
oldItem.anchor == newItem.anchor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [RecyclerView.ViewHolder] that displays a [Song] in the context of an [Album]. Use [from] to
|
||||
* create an instance.
|
||||
|
|
|
@ -6,57 +6,49 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingTop="@dimen/spacing_mid_medium"
|
||||
android:paddingTop="@dimen/spacing_small"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingBottom="@dimen/spacing_mid_medium">
|
||||
android:paddingBottom="@dimen/spacing_small">
|
||||
|
||||
<org.oxycblt.auxio.image.CoverView
|
||||
android:id="@+id/disc_cover"
|
||||
style="@style/Widget.Auxio.Image.Small"
|
||||
android:scaleType="matrix"
|
||||
app:enablePlaybackIndicator="false"
|
||||
app:enableSelectionBadge="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/disc_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_album_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="@color/sel_on_cover_bg"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</org.oxycblt.auxio.image.CoverView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/disc_number"
|
||||
style="@style/Widget.Auxio.TextView.Item.Primary"
|
||||
style="@style/Widget.Auxio.TextView.Primary.Compact"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
||||
android:layout_marginStart="@dimen/spacing_medium"
|
||||
android:textColor="@color/sel_selectable_text_primary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/disc_name"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/disc_cover"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/disc_icon"
|
||||
app:layout_constraintTop_toTopOf="@+id/disc_icon"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Disc 1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/disc_name"
|
||||
style="@style/Widget.Auxio.TextView.Item.Secondary"
|
||||
style="@style/Widget.Auxio.TextView.Secondary.Compact"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginStart="@dimen/spacing_medium"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/disc_icon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/disc_cover"
|
||||
app:layout_constraintStart_toEndOf="@+id/disc_icon"
|
||||
app:layout_constraintTop_toBottomOf="@+id/disc_number"
|
||||
tools:text="Part 1"
|
||||
tools:visibility="gone" />
|
||||
tools:text="Part 1" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in a new issue