list: unwind choiceviewholder
Unwind ChoiceViewHolder into specific impls. Was not re-usable enough w/playlists in order to be reasonable.
This commit is contained in:
parent
b2e899a211
commit
d1f9200bf9
11 changed files with 297 additions and 131 deletions
|
@ -44,9 +44,6 @@ import org.oxycblt.auxio.util.lazyReflectedField
|
||||||
* and thus scrolling past them should make the toolbar show the name in order to give context on
|
* and thus scrolling past them should make the toolbar show the name in order to give context on
|
||||||
* where the user currently is.
|
* where the user currently is.
|
||||||
*
|
*
|
||||||
* This task should nominally be accomplished with CollapsingToolbarLayout, but I have not figured
|
|
||||||
* out how to get that working sensibly yet.
|
|
||||||
*
|
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class DetailAppBarLayout
|
class DetailAppBarLayout
|
||||||
|
|
|
@ -24,10 +24,8 @@ import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.ItemHeaderBinding
|
import org.oxycblt.auxio.databinding.ItemHeaderBinding
|
||||||
import org.oxycblt.auxio.databinding.ItemParentBinding
|
import org.oxycblt.auxio.databinding.ItemParentBinding
|
||||||
import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding
|
|
||||||
import org.oxycblt.auxio.databinding.ItemSongBinding
|
import org.oxycblt.auxio.databinding.ItemSongBinding
|
||||||
import org.oxycblt.auxio.list.BasicHeader
|
import org.oxycblt.auxio.list.BasicHeader
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
|
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
|
||||||
|
@ -352,53 +350,3 @@ class BasicHeaderViewHolder private constructor(private val binding: ItemHeaderB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A [DialogRecyclerView.ViewHolder] that displays a smaller variant of a typical [T] item, for use
|
|
||||||
* in choice dialogs. Use [from] to create an instance.
|
|
||||||
*
|
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
|
||||||
*
|
|
||||||
* TODO: Unwind this into specific impls
|
|
||||||
*/
|
|
||||||
class ChoiceViewHolder<T : Music>
|
|
||||||
private constructor(private val binding: ItemPickerChoiceBinding) :
|
|
||||||
DialogRecyclerView.ViewHolder(binding.root) {
|
|
||||||
/**
|
|
||||||
* Bind new data to this instance.
|
|
||||||
*
|
|
||||||
* @param music The new [T] to bind.
|
|
||||||
* @param listener A [ClickableListListener] to bind interactions to.
|
|
||||||
*/
|
|
||||||
fun bind(music: T, listener: ClickableListListener<T>) {
|
|
||||||
listener.bind(music, this)
|
|
||||||
// ImageGroup is not generic, so we must downcast to specific types for now.
|
|
||||||
when (music) {
|
|
||||||
is Song -> binding.pickerImage.bind(music)
|
|
||||||
is Album -> binding.pickerImage.bind(music)
|
|
||||||
is Artist -> binding.pickerImage.bind(music)
|
|
||||||
is Genre -> binding.pickerImage.bind(music)
|
|
||||||
is Playlist -> binding.pickerImage.bind(music)
|
|
||||||
}
|
|
||||||
binding.pickerName.text = music.name.resolve(binding.context)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance.
|
|
||||||
*
|
|
||||||
* @param parent The parent to inflate this instance from.
|
|
||||||
* @return A new instance.
|
|
||||||
*/
|
|
||||||
fun <T : Music> from(parent: View) =
|
|
||||||
ChoiceViewHolder<T>(ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
|
||||||
|
|
||||||
/** Get a comparator that can be used with DiffUtil. */
|
|
||||||
fun <T : Music> diffCallback() =
|
|
||||||
object : SimpleDiffCallback<T>() {
|
|
||||||
override fun areContentsTheSame(oldItem: T, newItem: T) =
|
|
||||||
oldItem.name == newItem.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import androidx.recyclerview.widget.ConcatAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
@ -44,7 +44,7 @@ import org.oxycblt.auxio.util.showToast
|
||||||
*/
|
*/
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AddToPlaylistDialog :
|
class AddToPlaylistDialog :
|
||||||
ViewBindingDialogFragment<DialogMusicPickerBinding>(),
|
ViewBindingDialogFragment<DialogMusicChoicesBinding>(),
|
||||||
ClickableListListener<PlaylistChoice>,
|
ClickableListListener<PlaylistChoice>,
|
||||||
NewPlaylistFooterAdapter.Listener {
|
NewPlaylistFooterAdapter.Listener {
|
||||||
private val musicModel: MusicViewModel by activityViewModels()
|
private val musicModel: MusicViewModel by activityViewModels()
|
||||||
|
@ -60,12 +60,12 @@ class AddToPlaylistDialog :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
DialogMusicPickerBinding.inflate(inflater)
|
DialogMusicChoicesBinding.inflate(inflater)
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicChoicesBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
|
|
||||||
binding.pickerChoiceRecycler.apply {
|
binding.choiceRecycler.apply {
|
||||||
itemAnimator = null
|
itemAnimator = null
|
||||||
adapter = ConcatAdapter(choiceAdapter, footerAdapter)
|
adapter = ConcatAdapter(choiceAdapter, footerAdapter)
|
||||||
}
|
}
|
||||||
|
@ -76,9 +76,9 @@ class AddToPlaylistDialog :
|
||||||
collectImmediately(pickerModel.playlistChoices, ::updatePlaylistChoices)
|
collectImmediately(pickerModel.playlistChoices, ::updatePlaylistChoices)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
|
||||||
super.onDestroyBinding(binding)
|
super.onDestroyBinding(binding)
|
||||||
binding.pickerChoiceRecycler.adapter = null
|
binding.choiceRecycler.adapter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(item: PlaylistChoice, viewHolder: RecyclerView.ViewHolder) {
|
override fun onClick(item: PlaylistChoice, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* ArtistNavigationChoiceAdapter.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio.navigation.picker
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding
|
||||||
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
|
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
||||||
|
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
|
||||||
|
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||||
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.util.context
|
||||||
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [FlexibleListAdapter] that displays a list of [Artist] navigation choices, for use with
|
||||||
|
* [NavigateToArtistDialog].
|
||||||
|
*
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
class ArtistNavigationChoiceAdapter(private val listener: ClickableListListener<Artist>) :
|
||||||
|
FlexibleListAdapter<Artist, ArtistNavigationChoiceViewHolder>(
|
||||||
|
ArtistNavigationChoiceViewHolder.DIFF_CALLBACK) {
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
ArtistNavigationChoiceViewHolder.from(parent)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ArtistNavigationChoiceViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position), listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [DialogRecyclerView.ViewHolder] that displays a smaller variant of a typical [Artist] item, for
|
||||||
|
* use [ArtistNavigationChoiceAdapter]. Use [from] to create an instance.
|
||||||
|
*
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
class ArtistNavigationChoiceViewHolder
|
||||||
|
private constructor(private val binding: ItemPickerChoiceBinding) :
|
||||||
|
DialogRecyclerView.ViewHolder(binding.root) {
|
||||||
|
/**
|
||||||
|
* Bind new data to this instance.
|
||||||
|
*
|
||||||
|
* @param artist The new [Artist] to bind.
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
fun bind(artist: Artist, listener: ClickableListListener<Artist>) {
|
||||||
|
listener.bind(artist, this)
|
||||||
|
binding.pickerImage.bind(artist)
|
||||||
|
binding.pickerName.text = artist.name.resolve(binding.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param parent The parent to inflate this instance from.
|
||||||
|
* @return A new instance.
|
||||||
|
*/
|
||||||
|
fun from(parent: View) =
|
||||||
|
ArtistNavigationChoiceViewHolder(
|
||||||
|
ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
||||||
|
|
||||||
|
/** A comparator that can be used with DiffUtil. */
|
||||||
|
val DIFF_CALLBACK =
|
||||||
|
object : SimpleDiffCallback<Artist>() {
|
||||||
|
override fun areContentsTheSame(oldItem: Artist, newItem: Artist) =
|
||||||
|
oldItem.name == newItem.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ package org.oxycblt.auxio.navigation.picker
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
@ -29,11 +28,9 @@ import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
import org.oxycblt.auxio.list.recycler.ChoiceViewHolder
|
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.navigation.NavigationViewModel
|
import org.oxycblt.auxio.navigation.NavigationViewModel
|
||||||
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
||||||
|
@ -46,25 +43,25 @@ import org.oxycblt.auxio.util.collectImmediately
|
||||||
*/
|
*/
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class NavigateToArtistDialog :
|
class NavigateToArtistDialog :
|
||||||
ViewBindingDialogFragment<DialogMusicPickerBinding>(), ClickableListListener<Artist> {
|
ViewBindingDialogFragment<DialogMusicChoicesBinding>(), ClickableListListener<Artist> {
|
||||||
private val navigationModel: NavigationViewModel by activityViewModels()
|
private val navigationModel: NavigationViewModel by activityViewModels()
|
||||||
private val pickerModel: NavigationPickerViewModel by viewModels()
|
private val pickerModel: NavigationPickerViewModel by viewModels()
|
||||||
// Information about what artists to show choices for is initially within the navigation
|
// Information about what artists to show choices for is initially within the navigation
|
||||||
// arguments as UIDs, as that is the only safe way to parcel an artist.
|
// arguments as UIDs, as that is the only safe way to parcel an artist.
|
||||||
private val args: NavigateToArtistDialogArgs by navArgs()
|
private val args: NavigateToArtistDialogArgs by navArgs()
|
||||||
private val choiceAdapter = ArtistChoiceAdapter(this)
|
private val choiceAdapter = ArtistNavigationChoiceAdapter(this)
|
||||||
|
|
||||||
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
||||||
builder.setTitle(R.string.lbl_artists).setNegativeButton(R.string.lbl_cancel, null)
|
builder.setTitle(R.string.lbl_artists).setNegativeButton(R.string.lbl_cancel, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
DialogMusicPickerBinding.inflate(inflater)
|
DialogMusicChoicesBinding.inflate(inflater)
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicChoicesBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
|
|
||||||
binding.pickerChoiceRecycler.apply {
|
binding.choiceRecycler.apply {
|
||||||
itemAnimator = null
|
itemAnimator = null
|
||||||
adapter = choiceAdapter
|
adapter = choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -79,7 +76,7 @@ class NavigateToArtistDialog :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
|
||||||
super.onDestroyBinding(binding)
|
super.onDestroyBinding(binding)
|
||||||
choiceAdapter
|
choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -89,16 +86,4 @@ class NavigateToArtistDialog :
|
||||||
navigationModel.exploreNavigateTo(item)
|
navigationModel.exploreNavigateTo(item)
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ArtistChoiceAdapter(private val listener: ClickableListListener<Artist>) :
|
|
||||||
FlexibleListAdapter<Artist, ChoiceViewHolder<Artist>>(ChoiceViewHolder.diffCallback()) {
|
|
||||||
override fun onCreateViewHolder(
|
|
||||||
parent: ViewGroup,
|
|
||||||
viewType: Int
|
|
||||||
): ChoiceViewHolder<Artist> = ChoiceViewHolder.from(parent)
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ChoiceViewHolder<Artist>, position: Int) {
|
|
||||||
holder.bind(getItem(position), listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* ArtistPlaybackChoiceAdapter.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio.playback.picker
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding
|
||||||
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
|
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
||||||
|
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
|
||||||
|
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||||
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.util.context
|
||||||
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [FlexibleListAdapter] that displays a list of [Artist] playback choices, for use with
|
||||||
|
* [PlayFromArtistDialog].
|
||||||
|
*
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
class ArtistPlaybackChoiceAdapter(private val listener: ClickableListListener<Artist>) :
|
||||||
|
FlexibleListAdapter<Artist, ArtistPlaybackChoiceViewHolder>(
|
||||||
|
ArtistPlaybackChoiceViewHolder.DIFF_CALLBACK) {
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
ArtistPlaybackChoiceViewHolder.from(parent)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ArtistPlaybackChoiceViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position), listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [DialogRecyclerView.ViewHolder] that displays a smaller variant of a typical [Artist] item, for
|
||||||
|
* use [ArtistPlaybackChoiceAdapter]. Use [from] to create an instance.
|
||||||
|
*
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
class ArtistPlaybackChoiceViewHolder
|
||||||
|
private constructor(private val binding: ItemPickerChoiceBinding) :
|
||||||
|
DialogRecyclerView.ViewHolder(binding.root) {
|
||||||
|
/**
|
||||||
|
* Bind new data to this instance.
|
||||||
|
*
|
||||||
|
* @param artist The new [Artist] to bind.
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
fun bind(artist: Artist, listener: ClickableListListener<Artist>) {
|
||||||
|
listener.bind(artist, this)
|
||||||
|
binding.pickerImage.bind(artist)
|
||||||
|
binding.pickerName.text = artist.name.resolve(binding.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param parent The parent to inflate this instance from.
|
||||||
|
* @return A new instance.
|
||||||
|
*/
|
||||||
|
fun from(parent: View) =
|
||||||
|
ArtistPlaybackChoiceViewHolder(ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
||||||
|
|
||||||
|
/** A comparator that can be used with DiffUtil. */
|
||||||
|
val DIFF_CALLBACK =
|
||||||
|
object : SimpleDiffCallback<Artist>() {
|
||||||
|
override fun areContentsTheSame(oldItem: Artist, newItem: Artist) =
|
||||||
|
oldItem.name == newItem.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* GenrePlaybackChoiceAdapter.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio.playback.picker
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding
|
||||||
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
|
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
||||||
|
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
|
||||||
|
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||||
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
import org.oxycblt.auxio.util.context
|
||||||
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [FlexibleListAdapter] that displays a list of [Genre] playback choices, for use with
|
||||||
|
* [PlayFromGenreDialog].
|
||||||
|
*
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
class GenrePlaybackChoiceAdapter(private val listener: ClickableListListener<Genre>) :
|
||||||
|
FlexibleListAdapter<Genre, GenrePlaybackChoiceViewHolder>(
|
||||||
|
GenrePlaybackChoiceViewHolder.DIFF_CALLBACK) {
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
GenrePlaybackChoiceViewHolder.from(parent)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: GenrePlaybackChoiceViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position), listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [DialogRecyclerView.ViewHolder] that displays a smaller variant of a typical [Genre] item, for
|
||||||
|
* use [GenrePlaybackChoiceAdapter]. Use [from] to create an instance.
|
||||||
|
*
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
class GenrePlaybackChoiceViewHolder
|
||||||
|
private constructor(private val binding: ItemPickerChoiceBinding) :
|
||||||
|
DialogRecyclerView.ViewHolder(binding.root) {
|
||||||
|
/**
|
||||||
|
* Bind new data to this instance.
|
||||||
|
*
|
||||||
|
* @param artist The new [Genre] to bind.
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
fun bind(artist: Genre, listener: ClickableListListener<Genre>) {
|
||||||
|
listener.bind(artist, this)
|
||||||
|
binding.pickerImage.bind(artist)
|
||||||
|
binding.pickerName.text = artist.name.resolve(binding.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param parent The parent to inflate this instance from.
|
||||||
|
* @return A new instance.
|
||||||
|
*/
|
||||||
|
fun from(parent: View) =
|
||||||
|
GenrePlaybackChoiceViewHolder(ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
||||||
|
|
||||||
|
/** A comparator that can be used with DiffUtil. */
|
||||||
|
val DIFF_CALLBACK =
|
||||||
|
object : SimpleDiffCallback<Genre>() {
|
||||||
|
override fun areContentsTheSame(oldItem: Genre, newItem: Genre) =
|
||||||
|
oldItem.name == newItem.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ package org.oxycblt.auxio.playback.picker
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
@ -29,11 +28,9 @@ import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
import org.oxycblt.auxio.list.recycler.ChoiceViewHolder
|
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
||||||
|
@ -47,25 +44,25 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
*/
|
*/
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PlayFromArtistDialog :
|
class PlayFromArtistDialog :
|
||||||
ViewBindingDialogFragment<DialogMusicPickerBinding>(), ClickableListListener<Artist> {
|
ViewBindingDialogFragment<DialogMusicChoicesBinding>(), ClickableListListener<Artist> {
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
private val pickerModel: PlaybackPickerViewModel by viewModels()
|
private val pickerModel: PlaybackPickerViewModel by viewModels()
|
||||||
// Information about what Song to show choices for is initially within the navigation arguments
|
// Information about what Song to show choices for is initially within the navigation arguments
|
||||||
// as UIDs, as that is the only safe way to parcel a Song.
|
// as UIDs, as that is the only safe way to parcel a Song.
|
||||||
private val args: PlayFromArtistDialogArgs by navArgs()
|
private val args: PlayFromArtistDialogArgs by navArgs()
|
||||||
private val choiceAdapter = ArtistChoiceAdapter(this)
|
private val choiceAdapter = ArtistPlaybackChoiceAdapter(this)
|
||||||
|
|
||||||
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
||||||
builder.setTitle(R.string.lbl_artists).setNegativeButton(R.string.lbl_cancel, null)
|
builder.setTitle(R.string.lbl_artists).setNegativeButton(R.string.lbl_cancel, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
DialogMusicPickerBinding.inflate(inflater)
|
DialogMusicChoicesBinding.inflate(inflater)
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicChoicesBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
|
|
||||||
binding.pickerChoiceRecycler.apply {
|
binding.choiceRecycler.apply {
|
||||||
itemAnimator = null
|
itemAnimator = null
|
||||||
adapter = choiceAdapter
|
adapter = choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -80,7 +77,7 @@ class PlayFromArtistDialog :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
|
||||||
super.onDestroyBinding(binding)
|
super.onDestroyBinding(binding)
|
||||||
choiceAdapter
|
choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -91,16 +88,4 @@ class PlayFromArtistDialog :
|
||||||
playbackModel.playFromArtist(song, item)
|
playbackModel.playFromArtist(song, item)
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ArtistChoiceAdapter(private val listener: ClickableListListener<Artist>) :
|
|
||||||
FlexibleListAdapter<Artist, ChoiceViewHolder<Artist>>(ChoiceViewHolder.diffCallback()) {
|
|
||||||
override fun onCreateViewHolder(
|
|
||||||
parent: ViewGroup,
|
|
||||||
viewType: Int
|
|
||||||
): ChoiceViewHolder<Artist> = ChoiceViewHolder.from(parent)
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ChoiceViewHolder<Artist>, position: Int) {
|
|
||||||
holder.bind(getItem(position), listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ package org.oxycblt.auxio.playback.picker
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
@ -29,11 +28,9 @@ import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
import org.oxycblt.auxio.list.recycler.ChoiceViewHolder
|
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
||||||
|
@ -47,25 +44,25 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
*/
|
*/
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PlayFromGenreDialog :
|
class PlayFromGenreDialog :
|
||||||
ViewBindingDialogFragment<DialogMusicPickerBinding>(), ClickableListListener<Genre> {
|
ViewBindingDialogFragment<DialogMusicChoicesBinding>(), ClickableListListener<Genre> {
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
private val pickerModel: PlaybackPickerViewModel by viewModels()
|
private val pickerModel: PlaybackPickerViewModel by viewModels()
|
||||||
// Information about what Song to show choices for is initially within the navigation arguments
|
// Information about what Song to show choices for is initially within the navigation arguments
|
||||||
// as UIDs, as that is the only safe way to parcel a Song.
|
// as UIDs, as that is the only safe way to parcel a Song.
|
||||||
private val args: PlayFromGenreDialogArgs by navArgs()
|
private val args: PlayFromGenreDialogArgs by navArgs()
|
||||||
private val choiceAdapter = GenreChoiceAdapter(this)
|
private val choiceAdapter = GenrePlaybackChoiceAdapter(this)
|
||||||
|
|
||||||
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
||||||
builder.setTitle(R.string.lbl_genres).setNegativeButton(R.string.lbl_cancel, null)
|
builder.setTitle(R.string.lbl_genres).setNegativeButton(R.string.lbl_cancel, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
DialogMusicPickerBinding.inflate(inflater)
|
DialogMusicChoicesBinding.inflate(inflater)
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicChoicesBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
|
|
||||||
binding.pickerChoiceRecycler.apply {
|
binding.choiceRecycler.apply {
|
||||||
itemAnimator = null
|
itemAnimator = null
|
||||||
adapter = choiceAdapter
|
adapter = choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -80,7 +77,7 @@ class PlayFromGenreDialog :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
|
||||||
super.onDestroyBinding(binding)
|
super.onDestroyBinding(binding)
|
||||||
choiceAdapter
|
choiceAdapter
|
||||||
}
|
}
|
||||||
|
@ -91,14 +88,4 @@ class PlayFromGenreDialog :
|
||||||
playbackModel.playFromGenre(song, item)
|
playbackModel.playFromGenre(song, item)
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GenreChoiceAdapter(private val listener: ClickableListListener<Genre>) :
|
|
||||||
FlexibleListAdapter<Genre, ChoiceViewHolder<Genre>>(ChoiceViewHolder.diffCallback()) {
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChoiceViewHolder<Genre> =
|
|
||||||
ChoiceViewHolder.from(parent)
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ChoiceViewHolder<Genre>, position: Int) {
|
|
||||||
holder.bind(getItem(position), listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- TODO: Rename picker usages to choice usages now that the former is used more generally -->
|
|
||||||
<org.oxycblt.auxio.list.recycler.DialogRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
<org.oxycblt.auxio.list.recycler.DialogRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/picker_choice_recycler"
|
android:id="@+id/choice_recycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
@ -71,7 +71,7 @@
|
||||||
android:id="@+id/navigate_to_artist_dialog"
|
android:id="@+id/navigate_to_artist_dialog"
|
||||||
android:name="org.oxycblt.auxio.navigation.picker.NavigateToArtistDialog"
|
android:name="org.oxycblt.auxio.navigation.picker.NavigateToArtistDialog"
|
||||||
android:label="navigate_to_artist_dialog"
|
android:label="navigate_to_artist_dialog"
|
||||||
tools:layout="@layout/dialog_music_picker">
|
tools:layout="@layout/dialog_music_choices">
|
||||||
<argument
|
<argument
|
||||||
android:name="itemUid"
|
android:name="itemUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
android:id="@+id/play_from_artist_dialog"
|
android:id="@+id/play_from_artist_dialog"
|
||||||
android:name="org.oxycblt.auxio.playback.picker.PlayFromArtistDialog"
|
android:name="org.oxycblt.auxio.playback.picker.PlayFromArtistDialog"
|
||||||
android:label="play_from_artist_dialog"
|
android:label="play_from_artist_dialog"
|
||||||
tools:layout="@layout/dialog_music_picker">
|
tools:layout="@layout/dialog_music_choices">
|
||||||
<argument
|
<argument
|
||||||
android:name="artistUid"
|
android:name="artistUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
android:id="@+id/play_from_genre_dialog"
|
android:id="@+id/play_from_genre_dialog"
|
||||||
android:name="org.oxycblt.auxio.playback.picker.PlayFromGenreDialog"
|
android:name="org.oxycblt.auxio.playback.picker.PlayFromGenreDialog"
|
||||||
android:label="play_from_genre_dialog"
|
android:label="play_from_genre_dialog"
|
||||||
tools:layout="@layout/dialog_music_picker">
|
tools:layout="@layout/dialog_music_choices">
|
||||||
<argument
|
<argument
|
||||||
android:name="genreUid"
|
android:name="genreUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
|
|
Loading…
Reference in a new issue