playback: start cleaning up pager impl

Fix some immediate compile issues and some style nitpicks. This breaks
the system a bit, but I don't think I will have enough time to debug
fully for the forseeable future, so I want to get this out now.
This commit is contained in:
Alexander Capehart 2023-08-22 07:27:28 -06:00
parent 83ec0c13da
commit b3ef43b37e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 44 additions and 106 deletions

View file

@ -2,6 +2,9 @@
## dev ## dev
#### What's New
- Added ability to rewind/skip tracks by swiping back/forward
#### What's Fixed #### What's Fixed
- Fixed app restart being required when changing intelligent sorting - Fixed app restart being required when changing intelligent sorting
or music separator settings or music separator settings

View file

@ -39,12 +39,12 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.ListViewModel
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.pager.PlaybackPageListener
import org.oxycblt.auxio.playback.pager.PlaybackPagerAdapter
import org.oxycblt.auxio.playback.queue.QueueViewModel import org.oxycblt.auxio.playback.queue.QueueViewModel
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.playback.ui.PlaybackPagerAdapter
import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.playback.ui.StyledSeekBar
import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
@ -67,7 +67,7 @@ class PlaybackPanelFragment :
ViewBindingFragment<FragmentPlaybackPanelBinding>(), ViewBindingFragment<FragmentPlaybackPanelBinding>(),
Toolbar.OnMenuItemClickListener, Toolbar.OnMenuItemClickListener,
StyledSeekBar.Listener, StyledSeekBar.Listener,
PlaybackPageListener { PlaybackPagerAdapter.Listener {
private val playbackModel: PlaybackViewModel by activityViewModels() private val playbackModel: PlaybackViewModel by activityViewModels()
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()
private val queueModel: QueueViewModel by activityViewModels() private val queueModel: QueueViewModel by activityViewModels()
@ -111,27 +111,13 @@ class PlaybackPanelFragment :
} }
// cover carousel adapter // cover carousel adapter
coverAdapter = PlaybackPagerAdapter(this, viewLifecycleOwner) coverAdapter = PlaybackPagerAdapter(this)
binding.playbackCoverPager.apply { binding.playbackCoverPager.apply {
adapter = coverAdapter adapter = coverAdapter
registerOnPageChangeCallback(OnCoverChangedCallback(queueModel)) registerOnPageChangeCallback(OnCoverChangedCallback(queueModel))
val recycler = VP_RECYCLER_FIELD.get(this@apply) as RecyclerView val recycler = VP_RECYCLER_FIELD.get(this@apply) as RecyclerView
recycler.isNestedScrollingEnabled = false recycler.isNestedScrollingEnabled = false
} }
// Set up marquee on song information, alongside click handlers that navigate to each
// respective item.
binding.playbackSong.apply {
isSelected = true
setOnClickListener { navigateToCurrentSong() }
}
binding.playbackArtist.apply {
isSelected = true
setOnClickListener { navigateToCurrentArtist() }
}
binding.playbackAlbum.apply {
isSelected = true
setOnClickListener { navigateToCurrentAlbum() }
}
binding.playbackSeekBar.listener = this binding.playbackSeekBar.listener = this
@ -189,7 +175,7 @@ class PlaybackPanelFragment :
} }
private fun updateQueue(queue: List<Song>) { private fun updateQueue(queue: List<Song>) {
coverAdapter?.update(queue, queueModel.queueInstructions.flow.value) coverAdapter?.update(queue, UpdateInstructions.Diff)
} }
private fun updateQueuePosition(position: Int) { private fun updateQueuePosition(position: Int) {
@ -250,7 +236,7 @@ class PlaybackPanelFragment :
} }
override fun navigateToMenu() { override fun navigateToMenu() {
binding?.playbackToolbar?.showOverflowMenu() // TODO
} }
private class OnCoverChangedCallback(private val viewModel: QueueViewModel) : private class OnCoverChangedCallback(private val viewModel: QueueViewModel) :

View file

@ -1,30 +0,0 @@
/*
* Copyright (c) 2023 Auxio Project
* PlaybackPageListener.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.pager
interface PlaybackPageListener {
fun navigateToCurrentArtist()
fun navigateToCurrentAlbum()
fun navigateToCurrentSong()
fun navigateToMenu()
}

View file

@ -16,78 +16,50 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.playback.pager package org.oxycblt.auxio.playback.ui
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlin.jvm.internal.Intrinsics import kotlin.jvm.internal.Intrinsics
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ItemPlaybackSongBinding import org.oxycblt.auxio.databinding.ItemPlaybackSongBinding
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.inflater
class PlaybackPagerAdapter( /** @author Koitharu, Alexander Capehart (OxygenCobalt) */
private val listener: PlaybackPageListener, class PlaybackPagerAdapter(private val listener: Listener) : FlexibleListAdapter<Song, CoverViewHolder>(CoverViewHolder.DIFF_CALLBACK) {
private val lifecycleOwner: LifecycleOwner
) : FlexibleListAdapter<Song, CoverViewHolder>(CoverViewHolder.DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CoverViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CoverViewHolder {
return CoverViewHolder.from(parent, listener).also { return CoverViewHolder.from(parent)
lifecycleOwner.lifecycle.addObserver(it)
}
} }
override fun onBindViewHolder(holder: CoverViewHolder, position: Int) { override fun onBindViewHolder(holder: CoverViewHolder, position: Int) {
holder.bind(getItem(position)) holder.bind(getItem(position), listener)
} }
override fun onViewRecycled(holder: CoverViewHolder) { override fun onViewRecycled(holder: CoverViewHolder) {
holder.recycle() holder.recycle()
super.onViewRecycled(holder) super.onViewRecycled(holder)
} }
interface Listener {
fun navigateToCurrentArtist()
fun navigateToCurrentAlbum()
fun navigateToCurrentSong()
fun navigateToMenu()
}
} }
class CoverViewHolder class CoverViewHolder private constructor(private val binding: ItemPlaybackSongBinding) :
private constructor( RecyclerView.ViewHolder(binding.root), DefaultLifecycleObserver {
private val binding: ItemPlaybackSongBinding,
private val listener: PlaybackPageListener
) : RecyclerView.ViewHolder(binding.root), DefaultLifecycleObserver, View.OnClickListener {
init { init {
binding.playbackSong.setOnClickListener(this) binding.root.layoutParams =
binding.playbackArtist.setOnClickListener(this) RecyclerView.LayoutParams(
binding.playbackAlbum.setOnClickListener(this) RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT)
binding.playbackCover.setOnClickListener(this)
}
override fun onClick(v: View) {
when (v.id) {
R.id.playback_album -> listener.navigateToCurrentAlbum()
R.id.playback_artist -> listener.navigateToCurrentArtist()
R.id.playback_song -> listener.navigateToCurrentSong()
R.id.playback_cover -> listener.navigateToMenu()
}
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
setSelected(true)
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
setSelected(false)
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
owner.lifecycle.removeObserver(this)
} }
/** /**
@ -95,17 +67,27 @@ private constructor(
* *
* @param item The new [Song] to bind. * @param item The new [Song] to bind.
*/ */
fun bind(item: Song) { fun bind(item: Song, listener: PlaybackPagerAdapter.Listener) {
binding.playbackCover.bind(item)
val context = binding.root.context val context = binding.root.context
binding.playbackSong.text = item.name.resolve(context) // binding.playbackCover.bind(item)
binding.playbackArtist.text = item.artists.resolveNames(context) binding.playbackSong.apply {
binding.playbackAlbum.text = item.album.name.resolve(context) text = item.name.resolve(context)
setOnClickListener { listener.navigateToCurrentSong() }
}
binding.playbackArtist.apply {
text = item.artists.resolveNames(context)
setOnClickListener { listener.navigateToCurrentArtist() }
}
binding.playbackAlbum.apply {
text = item.album.name.resolve(context)
setOnClickListener { listener.navigateToCurrentAlbum() }
}
setSelected(true) setSelected(true)
} }
fun recycle() { fun recycle() {
// Marquee elements leak if they are not disabled when the views are destroyed. // Marquee elements leak if they are not disabled when the views are destroyed.
// TODO: Move to TextView impl to avoid having to deal with lifecycle here
setSelected(false) setSelected(false)
} }
@ -122,11 +104,8 @@ private constructor(
* @param parent The parent to inflate this instance from. * @param parent The parent to inflate this instance from.
* @return A new instance. * @return A new instance.
*/ */
fun from(parent: ViewGroup, listener: PlaybackPageListener) = fun from(parent: ViewGroup) =
CoverViewHolder( CoverViewHolder(ItemPlaybackSongBinding.inflate(parent.context.inflater))
ItemPlaybackSongBinding.inflate(parent.context.inflater, parent, false),
listener
)
/** A comparator that can be used with DiffUtil. */ /** A comparator that can be used with DiffUtil. */
val DIFF_CALLBACK = val DIFF_CALLBACK =