From 7394e87471f285af3919e8d8c0942be524dd8091 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sun, 25 Dec 2022 19:27:40 -0700 Subject: [PATCH] queue: redocument Redocument the queue module. --- .../java/org/oxycblt/auxio/MainActivity.kt | 6 +- .../detail/recycler/AlbumDetailAdapter.kt | 8 +- .../detail/recycler/ArtistDetailAdapter.kt | 14 +- .../auxio/detail/recycler/DetailAdapter.kt | 6 +- .../auxio/home/list/AlbumListFragment.kt | 4 +- .../auxio/home/list/ArtistListFragment.kt | 4 +- .../auxio/home/list/GenreListFragment.kt | 4 +- .../auxio/home/list/SongListFragment.kt | 4 +- .../org/oxycblt/auxio/home/tabs/TabAdapter.kt | 10 +- .../auxio/home/tabs/TabCustomizeDialog.kt | 2 +- .../main/java/org/oxycblt/auxio/list/Data.kt | 1 - .../org/oxycblt/auxio/list/ListFragment.kt | 2 +- .../java/org/oxycblt/auxio/list/Listeners.kt | 19 ++- .../auxio/list/recycler/ViewHolders.kt | 26 ++-- .../auxio/music/picker/ArtistChoiceAdapter.kt | 10 +- .../auxio/music/picker/ArtistPickerDialog.kt | 4 +- .../auxio/playback/queue/QueueAdapter.kt | 147 +++++++++++++----- .../queue/QueueBottomSheetBehavior.kt | 9 +- .../auxio/playback/queue/QueueDragCallback.kt | 39 +++-- .../auxio/playback/queue/QueueFragment.kt | 26 ++-- .../auxio/playback/queue/QueueViewModel.kt | 43 +++-- .../org/oxycblt/auxio/search/SearchAdapter.kt | 4 +- .../auxio/settings/accent/AccentAdapter.kt | 10 +- .../settings/accent/AccentCustomizeDialog.kt | 4 +- 24 files changed, 258 insertions(+), 148 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 77eaa6288..ffe500111 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -48,10 +48,12 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat * * TODO: Migrate to material animation system * - * TODO: Re-document project - * * TODO: Unit testing * + * TODO: Standardize from/new usage + * + * TODO: Standardize companion object usage + * * @author Alexander Capehart (OxygenCobalt) */ class MainActivity : AppCompatActivity() { diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt index e0da21c55..e89f7688f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt @@ -27,7 +27,7 @@ import org.oxycblt.auxio.databinding.ItemAlbumSongBinding import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemDiscHeaderBinding import org.oxycblt.auxio.detail.DiscHeader -import org.oxycblt.auxio.list.ExtendedListListener +import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter import org.oxycblt.auxio.list.recycler.SimpleItemCallback @@ -224,10 +224,10 @@ private class AlbumSongViewHolder private constructor(private val binding: ItemA /** * Bind new data to this instance. * @param song The new [Song] to bind. - * @param listener A [ExtendedListListener] to bind interactions to. + * @param listener A [SelectableListListener] to bind interactions to. */ - fun bind(song: Song, listener: ExtendedListListener) { - listener.bind(song, binding.root, binding.songMenu) + fun bind(song: Song, listener: SelectableListListener) { + listener.bind(this, song, binding.songMenu) binding.songTrack.apply { if (song.track != null) { diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt index 75e11ee26..44830fd53 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt @@ -26,7 +26,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemParentBinding import org.oxycblt.auxio.databinding.ItemSongBinding -import org.oxycblt.auxio.list.ExtendedListListener +import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter import org.oxycblt.auxio.list.recycler.SimpleItemCallback @@ -181,10 +181,10 @@ private class ArtistAlbumViewHolder private constructor(private val binding: Ite /** * Bind new data to this instance. * @param album The new [Album] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(album: Album, listener: ExtendedListListener) { - listener.bind(album, binding.root, binding.parentMenu) + fun bind(album: Album, listener: SelectableListListener) { + listener.bind(this, album, binding.parentMenu) binding.parentImage.bind(album) binding.parentName.text = album.resolveName(binding.context) binding.parentInfo.text = @@ -232,10 +232,10 @@ private class ArtistSongViewHolder private constructor(private val binding: Item /** * Bind new data to this instance. * @param song The new [Song] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(song: Song, listener: ExtendedListListener) { - listener.bind(song, binding.root, binding.songMenu) + fun bind(song: Song, listener: SelectableListListener) { + listener.bind(this, song, binding.songMenu) binding.songAlbumCover.bind(song) binding.songName.text = song.resolveName(binding.context) binding.songInfo.text = song.album.resolveName(binding.context) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt index 9e139a87e..051e5c45d 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt @@ -26,7 +26,7 @@ import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.databinding.ItemSortHeaderBinding import org.oxycblt.auxio.detail.SortHeader -import org.oxycblt.auxio.list.ExtendedListListener +import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.recycler.* @@ -87,8 +87,8 @@ abstract class DetailAdapter( differ.submitList(newList) } - /** An extended [ExtendedListListener] for [DetailAdapter] implementations. */ - interface Listener : ExtendedListListener { + /** An extended [SelectableListListener] for [DetailAdapter] implementations. */ + interface Listener : SelectableListListener { // TODO: Split off into sub-listeners if a collapsing toolbar is implemented. /** * Called when the play button in a detail header is pressed, requesting that the current diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt index 59e5e5ced..2b69905df 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt @@ -139,9 +139,9 @@ class AlbumListFragment : ListFragment(), FastScrollRec /** * A [SelectionIndicatorAdapter] that shows a list of [Album]s using [AlbumViewHolder]. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - private class AlbumAdapter(private val listener: ExtendedListListener) : + private class AlbumAdapter(private val listener: SelectableListListener) : SelectionIndicatorAdapter() { private val differ = SyncListDiffer(this, AlbumViewHolder.DIFF_CALLBACK) diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt index 2663d5ba8..09db6c8eb 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt @@ -114,9 +114,9 @@ class ArtistListFragment : ListFragment(), FastScrollRe /** * A [SelectionIndicatorAdapter] that shows a list of [Artist]s using [ArtistViewHolder]. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - private class ArtistAdapter(private val listener: ExtendedListListener) : + private class ArtistAdapter(private val listener: SelectableListListener) : SelectionIndicatorAdapter() { private val differ = SyncListDiffer(this, ArtistViewHolder.DIFF_CALLBACK) diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt index 0d085835f..9cbb5dd52 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt @@ -113,9 +113,9 @@ class GenreListFragment : ListFragment(), FastScrollRec /** * A [SelectionIndicatorAdapter] that shows a list of [Genre]s using [GenreViewHolder]. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - private class GenreAdapter(private val listener: ExtendedListListener) : + private class GenreAdapter(private val listener: SelectableListListener) : SelectionIndicatorAdapter() { private val differ = SyncListDiffer(this, GenreViewHolder.DIFF_CALLBACK) diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt index 212ab15ec..b9f50a428 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt @@ -153,9 +153,9 @@ class SongListFragment : ListFragment(), FastScrollRecy /** * A [SelectionIndicatorAdapter] that shows a list of [Song]s using [SongViewHolder]. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - private class SongAdapter(private val listener: ExtendedListListener) : + private class SongAdapter(private val listener: SelectableListListener) : SelectionIndicatorAdapter() { private val differ = SyncListDiffer(this, SongViewHolder.DIFF_CALLBACK) diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt index 6e73764ef..bef65495d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt @@ -85,10 +85,11 @@ class TabAdapter(private val listener: Listener) : RecyclerView.Adapter binding.tabDragHandle.performClick() if (motionEvent.actionMasked == MotionEvent.ACTION_DOWN) { - listener.onPickUpTab(this) + listener.onPickUp(this) true } else false } } companion object { - /** * Create a new instance. * @param parent The parent to inflate this instance from. diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt index 3b7262ec0..3379c1120 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt @@ -104,7 +104,7 @@ class TabCustomizeDialog : ViewBindingDialogFragment(), TabAd tabAdapter.tabs.filterIsInstance().isNotEmpty() } - override fun onPickUpTab(viewHolder: RecyclerView.ViewHolder) { + override fun onPickUp(viewHolder: RecyclerView.ViewHolder) { touchHelper.startDrag(viewHolder) } diff --git a/app/src/main/java/org/oxycblt/auxio/list/Data.kt b/app/src/main/java/org/oxycblt/auxio/list/Data.kt index 7fbea9f31..c5710bcbd 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Data.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Data.kt @@ -2,7 +2,6 @@ package org.oxycblt.auxio.list import androidx.annotation.StringRes - /** * A marker for something that is a RecyclerView item. Has no functionality on it's own. */ diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt index ab2230231..41c1450a3 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt @@ -36,7 +36,7 @@ import org.oxycblt.auxio.util.showToast * A Fragment containing a selectable list. * @author Alexander Capehart (OxygenCobalt) */ -abstract class ListFragment : SelectionFragment(), ExtendedListListener { +abstract class ListFragment : SelectionFragment(), SelectableListListener { protected val navModel: NavigationViewModel by activityViewModels() private var currentMenu: PopupMenu? = null diff --git a/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt b/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt index 2b30ca818..29437c259 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt @@ -1,12 +1,17 @@ package org.oxycblt.auxio.list +import android.view.MotionEvent import android.view.View import android.widget.Button +import android.widget.ImageView +import androidx.recyclerview.widget.RecyclerView /** * A basic listener for list interactions. + * TODO: Supply a ViewHolder on clicks (allows editable lists to be standardized into a listener.) + * @author Alexander Capehart (OxygenCobalt) */ -interface BasicListListener { +interface ClickableListListener { /** * Called when an [Item] in the list is clicked. * @param item The [Item] that was clicked. @@ -15,9 +20,10 @@ interface BasicListListener { } /** - * An extension of [BasicListListener] that enables menu and selection functionality. + * An extension of [ClickableListListener] that enables menu and selection functionality. + * @author Alexander Capehart (OxygenCobalt) */ -interface ExtendedListListener : BasicListListener { +interface SelectableListListener : ClickableListListener { /** * Called when an [Item] in the list requests that a menu related to it should be opened. * @param item The [Item] to show a menu for. @@ -33,12 +39,12 @@ interface ExtendedListListener : BasicListListener { /** * Binds this instance to a list item. + * @param viewHolder The [RecyclerView.ViewHolder] to bind. * @param item The [Item] that this list entry is bound to. - * @param root The root of the list [View]. * @param menuButton A [Button] that opens a menu. */ - fun bind(item: Item, root: View, menuButton: Button) { - root.apply { + fun bind(viewHolder: RecyclerView.ViewHolder, item: Item, menuButton: Button) { + viewHolder.itemView.apply { // Map clicks to the click callback. setOnClickListener { onClick(item) } // Map long clicks to the selection callback. @@ -47,7 +53,6 @@ interface ExtendedListListener : BasicListListener { true } } - // Map the menu button to the menu opening callback. menuButton.setOnClickListener { onOpenMenu(item, it) } } diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt index 4282a1b6b..e616512b7 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt @@ -24,7 +24,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.ItemHeaderBinding import org.oxycblt.auxio.databinding.ItemParentBinding import org.oxycblt.auxio.databinding.ItemSongBinding -import org.oxycblt.auxio.list.ExtendedListListener +import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -43,10 +43,10 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : /** * Bind new data to this instance. * @param song The new [Song] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(song: Song, listener: ExtendedListListener) { - listener.bind(song, binding.root, binding.songMenu) + fun bind(song: Song, listener: SelectableListListener) { + listener.bind(this, song, binding.songMenu) binding.songAlbumCover.bind(song) binding.songName.text = song.resolveName(binding.context) binding.songInfo.text = song.resolveArtistContents(binding.context) @@ -90,10 +90,10 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding /** * Bind new data to this instance. * @param album The new [Album] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(album: Album, listener: ExtendedListListener) { - listener.bind(album, binding.root, binding.parentMenu) + fun bind(album: Album, listener: SelectableListListener) { + listener.bind(this, album, binding.parentMenu) binding.parentImage.bind(album) binding.parentName.text = album.resolveName(binding.context) binding.parentInfo.text = album.resolveArtistContents(binding.context) @@ -139,10 +139,10 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin /** * Bind new data to this instance. * @param artist The new [Artist] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(artist: Artist, listener: ExtendedListListener) { - listener.bind(artist, binding.root, binding.parentMenu) + fun bind(artist: Artist, listener: SelectableListListener) { + listener.bind(this, artist, binding.parentMenu) binding.parentImage.bind(artist) binding.parentName.text = artist.resolveName(binding.context) binding.parentInfo.text = @@ -197,10 +197,10 @@ class GenreViewHolder private constructor(private val binding: ItemParentBinding /** * Bind new data to this instance. * @param genre The new [Genre] to bind. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. */ - fun bind(genre: Genre, listener: ExtendedListListener) { - listener.bind(genre, binding.root, binding.parentMenu) + fun bind(genre: Genre, listener: SelectableListListener) { + listener.bind(this, genre, binding.parentMenu) binding.parentImage.bind(genre) binding.parentName.text = genre.resolveName(binding.context) binding.parentInfo.text = diff --git a/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistChoiceAdapter.kt b/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistChoiceAdapter.kt index 44a4d6fab..8d23750a3 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistChoiceAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistChoiceAdapter.kt @@ -21,7 +21,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding -import org.oxycblt.auxio.list.BasicListListener +import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.list.recycler.DialogRecyclerView import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.util.context @@ -29,10 +29,10 @@ import org.oxycblt.auxio.util.inflater /** * An adapter responsible for showing a list of [Artist] choices in [ArtistPickerDialog]. - * @param listener A [BasicListListener] to bind interactions to. + * @param listener A [ClickableListListener] to bind interactions to. * @author OxygenCobalt. */ -class ArtistChoiceAdapter(private val listener: BasicListListener) : +class ArtistChoiceAdapter(private val listener: ClickableListListener) : RecyclerView.Adapter() { private var artists = listOf() @@ -65,9 +65,9 @@ class ArtistChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : /** * Bind new data to this instance. * @param artist The new [Artist] to bind. - * @param listener A [BasicListListener] to bind interactions to. + * @param listener A [ClickableListListener] to bind interactions to. */ - fun bind(artist: Artist, listener: BasicListListener) { + fun bind(artist: Artist, listener: ClickableListListener) { binding.root.setOnClickListener { listener.onClick(artist) } binding.pickerImage.bind(artist) binding.pickerName.text = artist.resolveName(binding.context) diff --git a/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistPickerDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistPickerDialog.kt index e105964d8..c5c3380df 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistPickerDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/picker/ArtistPickerDialog.kt @@ -24,7 +24,7 @@ import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogMusicPickerBinding -import org.oxycblt.auxio.list.BasicListListener +import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.shared.ViewBindingDialogFragment @@ -36,7 +36,7 @@ import org.oxycblt.auxio.util.collectImmediately * multiple [Artist]'s to choose from. * @author Alexander Capehart (OxygenCobalt) */ -abstract class ArtistPickerDialog : ViewBindingDialogFragment(), BasicListListener { +abstract class ArtistPickerDialog : ViewBindingDialogFragment(), ClickableListListener { protected val pickerModel: PickerViewModel by viewModels() // Okay to leak this since the Listener will not be called until after initialization. private val artistAdapter = ArtistChoiceAdapter(@Suppress("LeakingThis") this) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index a65d67b30..1b406d205 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -36,9 +36,17 @@ import org.oxycblt.auxio.util.getAttrColorCompat import org.oxycblt.auxio.util.getDimen import org.oxycblt.auxio.util.inflater -class QueueAdapter(private val listener: QueueItemListener) : +/** + * A [RecyclerView.Adapter] that shows an editable list of queue items. + * @param listener A [Listener] to bind interactions to. + * @author Alexander Capehart (OxygenCobalt) + */ +class QueueAdapter(private val listener: Listener) : RecyclerView.Adapter() { private var differ = SyncListDiffer(this, QueueSongViewHolder.DIFF_CALLBACK) + // Since PlayingIndicator adapter relies on an item value, we cannot use it for this + // adapter, as one item can appear at several points in the UI. Use a similar implementation + // with an index value instead. private var currentIndex = 0 private var isPlaying = false @@ -59,63 +67,106 @@ class QueueAdapter(private val listener: QueueItemListener) : viewHolder.bind(differ.currentList[position], listener) } - viewHolder.isEnabled = position > currentIndex + viewHolder.isFuture = position > currentIndex viewHolder.updatePlayingIndicator(position == currentIndex, isPlaying) } + /** + * Synchronously update the list with new items. This is exceedingly slow for large diffs, + * so only use it for trivial updates. + * @param newList The new [Song]s for the adapter to display. + */ fun submitList(newList: List) { differ.submitList(newList) } + /** + * Replace the list with a new list. This is exceedingly slow for large diffs, + * so only use it for trivial updates. + * @param newList The new [Song]s for the adapter to display. + */ fun replaceList(newList: List) { differ.replaceList(newList) } - fun updateIndicator(index: Int, isPlaying: Boolean) { + /** + * Set the position of the currently playing item in the queue. This will mark the item + * as playing and any previous items as played. + * @param index The position of the currently playing item in the queue. + * @param isPlaying Whether playback is ongoing or paused. + */ + fun setPosition(index: Int, isPlaying: Boolean) { var updatedIndex = false if (index != currentIndex) { - when { - index < currentIndex -> { - val lastIndex = currentIndex - currentIndex = index - notifyItemRangeChanged(0, lastIndex + 1, PAYLOAD_UPDATE_INDEX) - } - else -> { - currentIndex = index - notifyItemRangeChanged(0, currentIndex + 1, PAYLOAD_UPDATE_INDEX) - } - } - + val lastIndex = currentIndex + currentIndex = index updatedIndex = true + + // Have to update not only the currently playing item, but also all items marked + // as playing. + if (currentIndex < lastIndex) { + notifyItemRangeChanged(0, lastIndex + 1, PAYLOAD_UPDATE_POSITION) + } else { + notifyItemRangeChanged(0, currentIndex + 1, PAYLOAD_UPDATE_POSITION) + } } if (this.isPlaying != isPlaying) { this.isPlaying = isPlaying - + // Don't need to do anything if we've already sent an update from changing the + // index. if (!updatedIndex) { - notifyItemChanged(index, PAYLOAD_UPDATE_INDEX) + notifyItemChanged(index, PAYLOAD_UPDATE_POSITION) } } } + /** + * A listener for queue list events. + */ + interface Listener { + /** + * Called when a [RecyclerView.ViewHolder] in the list as clicked. + * @param viewHolder The [RecyclerView.ViewHolder] that was clicked. + */ + fun onClick(viewHolder: RecyclerView.ViewHolder) + + /** + * Called when the drag handle on a [RecyclerView.ViewHolder] is clicked, requesting that a + * drag should be started. + * @param viewHolder The [RecyclerView.ViewHolder] to start dragging. + */ + fun onPickUp(viewHolder: RecyclerView.ViewHolder) + } + companion object { - val PAYLOAD_UPDATE_INDEX = Any() + private val PAYLOAD_UPDATE_POSITION = Any() } } -interface QueueItemListener { - fun onClick(viewHolder: RecyclerView.ViewHolder) - fun onPickUp(viewHolder: RecyclerView.ViewHolder) -} - +/** + * A [PlayingIndicatorAdapter.ViewHolder] that displays a queue [Song]. Use [new] to create an + * instance. + * @author Alexander Capehart (OxygenCobalt) + */ class QueueSongViewHolder private constructor(private val binding: ItemQueueSongBinding) : PlayingIndicatorAdapter.ViewHolder(binding.root) { + /** + * The "body" view of this [QueueSongViewHolder] that shows the [Song] information. + */ val bodyView: View get() = binding.body + + /** + * The background view of this [QueueSongViewHolder] that shows the delete icon. + */ val backgroundView: View get() = binding.background + /** + * The actual background drawable of this [QueueSongViewHolder] that can be manipulated. + */ val backgroundDrawable = MaterialShapeDrawable.createWithElevationOverlay(binding.root.context).apply { fillColor = binding.context.getAttrColorCompat(R.attr.colorSurface) @@ -123,6 +174,19 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong alpha = 0 } + /** + * If this queue item is considered "in the future" (i.e has not played yet). + */ + var isFuture: Boolean + get() = binding.songAlbumCover.isEnabled + set(value) { + // Don't want to disable clicking, just indicate the body and handle is disabled + binding.songAlbumCover.isEnabled = value + binding.songName.isEnabled = value + binding.songInfo.isEnabled = value + binding.songDragHandle.isEnabled = value + } + init { binding.body.background = LayerDrawable( @@ -134,17 +198,24 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong backgroundDrawable)) } + /** + * Bind new data to this instance. + * @param song The new [Song] to bind. + * @param listener A [QueueAdapter.Listener] to bind interactions to. + */ @SuppressLint("ClickableViewAccessibility") - fun bind(item: Song, listener: QueueItemListener) { - binding.songAlbumCover.bind(item) - binding.songName.text = item.resolveName(binding.context) - binding.songInfo.text = item.resolveArtistContents(binding.context) + fun bind(song: Song, listener: QueueAdapter.Listener) { + binding.body.setOnClickListener { + listener.onClick(this) + } + binding.songAlbumCover.bind(song) + binding.songName.text = song.resolveName(binding.context) + binding.songInfo.text = song.resolveArtistContents(binding.context) + // TODO: Why is this here? binding.background.isInvisible = true - binding.body.setOnClickListener { listener.onClick(this) } - - // Roll our own drag handlers as the default ones suck + // Set up the drag handle to start a drag whenever it is touched. binding.songDragHandle.setOnTouchListener { _, motionEvent -> binding.songDragHandle.performClick() if (motionEvent.actionMasked == MotionEvent.ACTION_DOWN) { @@ -154,25 +225,21 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong } } - var isEnabled: Boolean - get() = binding.songAlbumCover.isEnabled - set(value) { - // Don't want to disable clicking, just indicate the body and handle is disabled - binding.songAlbumCover.isEnabled = value - binding.songName.isEnabled = value - binding.songInfo.isEnabled = value - binding.songDragHandle.isEnabled = value - } - override fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) { binding.interactBody.isSelected = isActive binding.songAlbumCover.isPlaying = isPlaying } companion object { + /** + * Create a new instance. + * @param parent The parent to inflate this instance from. + * @return A new instance. + */ fun new(parent: View) = QueueSongViewHolder(ItemQueueSongBinding.inflate(parent.context.inflater)) + /** A comparator that can be used with DiffUtil. */ val DIFF_CALLBACK = SongViewHolder.DIFF_CALLBACK } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt index 361c334c1..170c08cad 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt @@ -32,7 +32,8 @@ import org.oxycblt.auxio.util.replaceSystemBarInsetsCompat import org.oxycblt.auxio.util.systemBarInsetsCompat /** - * The bottom sheet behavior designed for the queue in particular. + * The [BaseBottomSheetBehavior] for the queue bottom sheet. This is placed within the playback + * sheet and automatically arranges itself to show the playback bar at the top. * @author Alexander Capehart (OxygenCobalt) */ class QueueBottomSheetBehavior(context: Context, attributeSet: AttributeSet?) : @@ -41,6 +42,7 @@ class QueueBottomSheetBehavior(context: Context, attributeSet: Attribu private var barSpacing = context.getDimenPixels(R.dimen.spacing_small) init { + // Not hide-able (and not programmatically hide-able) isHideable = false } @@ -53,18 +55,19 @@ class QueueBottomSheetBehavior(context: Context, attributeSet: Attribu dependency: View ): Boolean { barHeight = dependency.height - return false // No change, just grabbed the height + // No change, just grabbed the height + return false } override fun createBackground(context: Context) = MaterialShapeDrawable.createWithElevationOverlay(context).apply { + // The queue sheet's background is a static elevated background. fillColor = context.getAttrColorCompat(R.attr.colorSurface) elevation = context.getDimen(R.dimen.elevation_normal) } override fun applyWindowInsets(child: View, insets: WindowInsets): WindowInsets { super.applyWindowInsets(child, insets) - // Offset our expanded panel by the size of the playback bar, as that is shown when // we slide up the panel. val bars = insets.systemBarInsetsCompat diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt index 8edcae373..a35c96a1b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt @@ -24,12 +24,12 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.R import org.oxycblt.auxio.util.getDimen +import org.oxycblt.auxio.util.getInteger import org.oxycblt.auxio.util.logD /** - * A highly customized [ItemTouchHelper.Callback] that handles the queue system while basically - * rebuilding most the "Material-y" aspects of an editable list because Google's implementations are - * hot garbage. This shouldn't have *too many* UI bugs. I hope. + * A highly customized [ItemTouchHelper.Callback] that enables some extra eye candy in the queue + * UI, such as an animation when lifting items. * @author Alexander Capehart (OxygenCobalt) */ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHelper.Callback() { @@ -40,11 +40,13 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe viewHolder: RecyclerView.ViewHolder ): Int { val queueHolder = viewHolder as QueueSongViewHolder - return if (queueHolder.isEnabled) { + return if (queueHolder.isFuture) { makeFlag( ItemTouchHelper.ACTION_STATE_DRAG, ItemTouchHelper.UP or ItemTouchHelper.DOWN) or makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE, ItemTouchHelper.START) } else { + // Avoid allowing any touch actions for already-played queue items, as the playback + // system does not currently allow for this. 0 } } @@ -58,12 +60,11 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe actionState: Int, isCurrentlyActive: Boolean ) { - // The material design page on elevation has a cool example of draggable items elevating - // themselves when being dragged. Too bad google's implementation of this doesn't even - // work! To emulate it on my own, I check if this child is in a drag state and then animate - // an elevation change. val holder = viewHolder as QueueSongViewHolder + // Hook drag events to "lifting" the queue item (i.e raising it's elevation). Make sure + // this is only done once when the item is initially picked up. + // TODO: I think this is possible to improve with a raw ValueAnimator. if (shouldLift && isCurrentlyActive && actionState == ItemTouchHelper.ACTION_STATE_DRAG) { logD("Lifting queue item") @@ -72,7 +73,7 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe holder.itemView .animate() .translationZ(elevation) - .setDuration(100) + .setDuration(recyclerView.context.getInteger(R.integer.anim_fade_exit_duration).toLong()) .setUpdateListener { bg.alpha = ((holder.itemView.translationZ / elevation) * 255).toInt() } @@ -82,20 +83,19 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe shouldLift = false } - // We show a background with a clear icon behind the queue song each time one is swiped - // away. To avoid any canvas shenanigans, we just place a custom background view behind the - // main "body" layout of the queue item and then translate that. - // + // We show a background with a delete icon behind the queue song each time one is swiped + // away. To avoid working with canvas, this is simply placed behind the queue body. // That comes with a couple of problems, however. For one, the background view will always // lag behind the body view, resulting in a noticeable pixel offset when dragging. To fix // this, we make this a separate view and make this view invisible whenever the item is - // not being swiped. We cannot merge this view with the FrameLayout, as that will cause - // another weird pixel desynchronization issue that is less visible but still incredibly - // annoying. + // not being swiped. This issue is also the reason why the background is not merged with + // the FrameLayout within the queue item. if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { holder.backgroundView.isInvisible = dX == 0f } + // Update other translations. We do not call the default implementation, so we must do + // this ourselves. holder.bodyView.translationX = dX holder.itemView.translationY = dY } @@ -104,6 +104,8 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe // When an elevated item is cleared, we reset the elevation using another animation. val holder = viewHolder as QueueSongViewHolder + // This function can be called multiple times, so only start the animation when the view's + // translationZ is already non-zero. if (holder.itemView.translationZ != 0f) { logD("Dropping queue item") @@ -112,7 +114,7 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe holder.itemView .animate() .translationZ(0f) - .setDuration(100) + .setDuration(recyclerView.context.getInteger(R.integer.anim_fade_exit_duration).toLong()) .setUpdateListener { bg.alpha = ((holder.itemView.translationZ / elevation) * 255).toInt() } @@ -122,6 +124,8 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe shouldLift = true + // Reset translations. We do not call the default implementation, so we must do + // this ourselves. holder.bodyView.translationX = 0f holder.itemView.translationY = 0f } @@ -138,5 +142,6 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe playbackModel.removeQueueDataItem(viewHolder.bindingAdapterPosition) } + // Long-press events are too buggy, only allow dragging with the handle. override fun isLongPressDragEnabled() = false } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt index b204ef8ac..db4d5cebf 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt @@ -19,7 +19,6 @@ package org.oxycblt.auxio.playback.queue import android.os.Bundle import android.view.LayoutInflater -import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -33,11 +32,10 @@ import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.logD /** - * A [Fragment] that shows the queue and enables editing as well. - * + * A [ViewBindingFragment] that displays an editable queue. * @author Alexander Capehart (OxygenCobalt) */ -class QueueFragment : ViewBindingFragment(), QueueItemListener { +class QueueFragment : ViewBindingFragment(), QueueAdapter.Listener { private val queueModel: QueueViewModel by activityViewModels() private val playbackModel: PlaybackViewModel by androidActivityViewModels() private val queueAdapter = QueueAdapter(this) @@ -48,13 +46,15 @@ class QueueFragment : ViewBindingFragment(), QueueItemList override fun onCreateBinding(inflater: LayoutInflater) = FragmentQueueBinding.inflate(inflater) override fun onBindingCreated(binding: FragmentQueueBinding, savedInstanceState: Bundle?) { + super.onBindingCreated(binding, savedInstanceState) + + // --- UI SETUP --- binding.queueRecycler.apply { adapter = queueAdapter touchHelper.attachToRecyclerView(this) } // --- VIEWMODEL SETUP ---- - collectImmediately( queueModel.queue, queueModel.index, playbackModel.isPlaying, ::updateQueue) } @@ -65,6 +65,7 @@ class QueueFragment : ViewBindingFragment(), QueueItemList } override fun onClick(viewHolder: RecyclerView.ViewHolder) { + // Clicking on a queue item should start playing it. queueModel.goto(viewHolder.bindingAdapterPosition) } @@ -75,31 +76,34 @@ class QueueFragment : ViewBindingFragment(), QueueItemList private fun updateQueue(queue: List, index: Int, isPlaying: Boolean) { val binding = requireBinding() - val replaceQueue = queueModel.replaceQueue - if (replaceQueue == true) { + // Replace or diff the queue depending on the type of change it is. + // TODO: Extend this to the whole app. + if (queueModel.replaceQueue == true) { logD("Replacing queue") queueAdapter.replaceList(queue) } else { logD("Diffing queue") queueAdapter.submitList(queue) } - queueModel.finishReplace() + // If requested, scroll to a new item (occurs when the index moves) val scrollTo = queueModel.scrollTo if (scrollTo != null) { + // Do not scroll to indices that are not in the currently visible range. + // This prevents the queue from jumping around when the user is trying to + // navigate the queue. val lmm = binding.queueRecycler.layoutManager as LinearLayoutManager val start = lmm.findFirstCompletelyVisibleItemPosition() val end = lmm.findLastCompletelyVisibleItemPosition() - if (scrollTo !in start..end) { logD("Scrolling to new position") binding.queueRecycler.scrollToPosition(scrollTo) } } - queueModel.finishScrollTo() - queueAdapter.updateIndicator(index, isPlaying) + // Update currently playing item + queueAdapter.setPosition(index, isPlaying) } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt index 7fb00ac88..6afe6d5f3 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt @@ -25,21 +25,25 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.state.PlaybackStateManager /** - * Class enabling more advanced queue list functionality and queue editing. TODO: Allow editing - * previous parts of the queue + * A [ViewModel] that manages the current queue state and allows navigation through the queue. + * * @author Alexander Capehart (OxygenCobalt) */ class QueueViewModel : ViewModel(), PlaybackStateManager.Callback { private val playbackManager = PlaybackStateManager.getInstance() private val _queue = MutableStateFlow(listOf()) + /** The current queue. */ val queue: StateFlow> = _queue private val _index = MutableStateFlow(playbackManager.index) + /** The index of the currently playing song in the queue. */ val index: StateFlow get() = _index + /** Whether to replace or diff the queue list when updating it. Is null if not specified. */ var replaceQueue: Boolean? = null + /** Flag to scroll to a particular queue item. Is null if no command has been specified. */ var scrollTo: Int? = null init { @@ -47,58 +51,78 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Callback { } /** - * Go to an item in the queue using it's recyclerview adapter index. No-ops if out of bounds. + * Start playing the the queue item at the given index. + * @param adapterIndex The index of the queue item to play. Does nothing if the index is out + * of range. */ fun goto(adapterIndex: Int) { if (adapterIndex !in playbackManager.queue.indices) { + // Invalid input. Nothing to do. return } - playbackManager.goto(adapterIndex) } - /** Remove a queue item using it's recyclerview adapter index. */ + /** + * Remove a queue item at the given index. + * @param adapterIndex The index of the queue item to play. Does nothing if the index is + * out of range. + */ fun removeQueueDataItem(adapterIndex: Int) { if (adapterIndex <= playbackManager.index || adapterIndex !in playbackManager.queue.indices) { + // Invalid input. Nothing to do. + // TODO: Allow editing played queue items. return } - playbackManager.removeQueueItem(adapterIndex) } - /** Move queue items using their recyclerview adapter indices. */ + /** + * Move a queue item from one index to another index. + * @param adapterFrom The index of the queue item to move. + * @param adapterTo The destination index for the queue item. + * @return true if the items were moved, false otherwise. + */ fun moveQueueDataItems(adapterFrom: Int, adapterTo: Int): Boolean { if (adapterFrom <= playbackManager.index || adapterTo <= playbackManager.index) { + // Invalid input. Nothing to do. return false } - playbackManager.moveQueueItem(adapterFrom, adapterTo) - return true } + /** + * Finish a replace flag specified by [replaceQueue]. + */ fun finishReplace() { replaceQueue = null } + /** + * Finish a scroll operation started by [scrollTo]. + */ fun finishScrollTo() { scrollTo = null } override fun onIndexMoved(index: Int) { + // Index moved -> Scroll to new index replaceQueue = null scrollTo = index _index.value = index } override fun onQueueChanged(queue: List) { + // Queue changed trivially due to item move -> Diff queue, stay at current index. replaceQueue = false scrollTo = null _queue.value = playbackManager.queue.toMutableList() } override fun onQueueReworked(index: Int, queue: List) { + // Queue changed completely -> Replace queue, update index replaceQueue = true scrollTo = index _queue.value = playbackManager.queue.toMutableList() @@ -106,6 +130,7 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Callback { } override fun onNewPlayback(index: Int, queue: List, parent: MusicParent?) { + // Entirely new queue -> Replace queue, update index replaceQueue = true scrollTo = index _queue.value = playbackManager.queue.toMutableList() diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt index ad076bd0c..0a1242272 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt @@ -29,10 +29,10 @@ import org.oxycblt.auxio.music.Song /** * An adapter that displays search results. - * @param listener An [ExtendedListListener] to bind interactions to. + * @param listener An [SelectableListListener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ -class SearchAdapter(private val listener: ExtendedListListener) : +class SearchAdapter(private val listener: SelectableListListener) : SelectionIndicatorAdapter(), AuxioRecyclerView.SpanSizeLookup { private val differ = AsyncListDiffer(this, DIFF_CALLBACK) diff --git a/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentAdapter.kt b/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentAdapter.kt index 7d40fcebc..803bd1de4 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentAdapter.kt @@ -23,17 +23,17 @@ import androidx.appcompat.widget.TooltipCompat import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.ItemAccentBinding -import org.oxycblt.auxio.list.BasicListListener +import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.util.getAttrColorCompat import org.oxycblt.auxio.util.getColorCompat import org.oxycblt.auxio.util.inflater /** * A [RecyclerView.Adapter] that displays [Accent] choices. - * @param listener A [BasicListListener] to bind interactions to. + * @param listener A [ClickableListListener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ -class AccentAdapter(private val listener: BasicListListener) : +class AccentAdapter(private val listener: ClickableListListener) : RecyclerView.Adapter() { /** The currently selected [Accent]. */ var selectedAccent: Accent? = null @@ -90,9 +90,9 @@ class AccentViewHolder private constructor(private val binding: ItemAccentBindin /** * Bind new data to this instance. * @param accent The new [Accent] to bind. - * @param listener A [BasicListListener] to bind interactions to. + * @param listener A [ClickableListListener] to bind interactions to. */ - fun bind(accent: Accent, listener: BasicListListener) { + fun bind(accent: Accent, listener: ClickableListListener) { binding.accent.apply { setOnClickListener { listener.onClick(accent) } backgroundTintList = context.getColorCompat(accent.primary) diff --git a/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentCustomizeDialog.kt index ba1ad5141..789ddd2ba 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/accent/AccentCustomizeDialog.kt @@ -23,7 +23,7 @@ import androidx.appcompat.app.AlertDialog import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogAccentBinding -import org.oxycblt.auxio.list.BasicListListener +import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.shared.ViewBindingDialogFragment @@ -35,7 +35,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull * A [ViewBindingDialogFragment] that allows the user to configure the current [Accent]. * @author Alexander Capehart (OxygenCobalt) */ -class AccentCustomizeDialog : ViewBindingDialogFragment(), BasicListListener { +class AccentCustomizeDialog : ViewBindingDialogFragment(), ClickableListListener { private var accentAdapter = AccentAdapter(this) private val settings: Settings by lifecycleObject { binding -> Settings(binding.context) }