Fix issues with PlaybackFragment seekbar
Fix bugs where PlaybackFragment's seekbar would update the player on the fly/flip out if PlaybackService updated the position while it was seeking.
This commit is contained in:
parent
1afaae7b0a
commit
ac5e6ba140
4 changed files with 49 additions and 18 deletions
|
@ -134,8 +134,10 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
}
|
||||
|
||||
playbackModel.positionAsProgress.observe(viewLifecycleOwner) {
|
||||
if (!playbackModel.isSeeking.value!!) {
|
||||
binding.playbackSeekBar.progress = it
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(this::class.simpleName, "Fragment Created.")
|
||||
|
||||
|
@ -145,7 +147,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
// Seeking callbacks
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
playbackModel.updatePositionWithProgress(progress)
|
||||
playbackModel.updatePositionDisplay(progress)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,5 +157,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
playbackModel.setSeekingStatus(false)
|
||||
|
||||
playbackModel.updatePosition(seekBar.progress)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.oxycblt.auxio.music.toURI
|
|||
import org.oxycblt.auxio.playback.state.PlaybackStateCallback
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
|
||||
// A Service that manages the single ExoPlayer instance and [attempts] to keep
|
||||
// persistence if the app closes.
|
||||
class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
|
||||
private val player: SimpleExoPlayer by lazy {
|
||||
val p = SimpleExoPlayer.Builder(applicationContext).build()
|
||||
|
@ -54,8 +56,16 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
|
|||
super.onDestroy()
|
||||
|
||||
player.release()
|
||||
playbackManager.removeCallback(this)
|
||||
serviceJob.cancel()
|
||||
playbackManager.removeCallback(this)
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(state: Int) {
|
||||
if (state == Player.STATE_ENDED) {
|
||||
playbackManager.next()
|
||||
} else if (state == Player.STATE_READY) {
|
||||
startPollingPosition()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSongUpdate(song: Song?) {
|
||||
|
@ -100,14 +110,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(state: Int) {
|
||||
if (state == Player.STATE_ENDED) {
|
||||
playbackManager.skipNext()
|
||||
} else if (state == Player.STATE_READY) {
|
||||
startPollingPosition()
|
||||
}
|
||||
}
|
||||
|
||||
inner class LocalBinder : Binder() {
|
||||
fun getService() = this@PlaybackService
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
|||
import org.oxycblt.auxio.playback.state.PlaybackStateCallback
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
|
||||
// The UI frontend for PlaybackStateManager.
|
||||
// A ViewModel that acts as an intermediary between the UI and PlaybackStateManager
|
||||
// TODO: Implement Looping Modes
|
||||
// TODO: Implement User Queue
|
||||
// TODO: Implement Persistence through Bundles/Databases/Idk
|
||||
class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackStateCallback {
|
||||
// Playback
|
||||
private val mSong = MutableLiveData<Song>()
|
||||
|
@ -88,14 +91,17 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
|
||||
// --- PLAYING FUNCTIONS ---
|
||||
|
||||
// Play a song
|
||||
fun playSong(song: Song, mode: PlaybackMode) {
|
||||
playbackManager.playSong(song, mode)
|
||||
}
|
||||
|
||||
// Play all songs
|
||||
fun shuffleAll() {
|
||||
playbackManager.shuffleAll()
|
||||
}
|
||||
|
||||
// Play an album
|
||||
fun playAlbum(album: Album, shuffled: Boolean) {
|
||||
if (album.songs.isEmpty()) {
|
||||
Log.e(this::class.simpleName, "Album is empty, Not playing.")
|
||||
|
@ -106,6 +112,7 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
playbackManager.playParentModel(album, shuffled)
|
||||
}
|
||||
|
||||
// Play an artist
|
||||
fun playArtist(artist: Artist, shuffled: Boolean) {
|
||||
if (artist.songs.isEmpty()) {
|
||||
Log.e(this::class.simpleName, "Artist is empty, Not playing.")
|
||||
|
@ -116,6 +123,7 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
playbackManager.playParentModel(artist, shuffled)
|
||||
}
|
||||
|
||||
// Play a genre
|
||||
fun playGenre(genre: Genre, shuffled: Boolean) {
|
||||
if (genre.songs.isEmpty()) {
|
||||
Log.e(this::class.simpleName, "Genre is empty, Not playing.")
|
||||
|
@ -128,7 +136,15 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
|
||||
// --- POSITION FUNCTIONS ---
|
||||
|
||||
fun updatePositionWithProgress(progress: Int) {
|
||||
// Update the position without pushing the change to playbackManager.
|
||||
// This is used during seek events to give the user an idea of where they're seeking to.
|
||||
fun updatePositionDisplay(progress: Int) {
|
||||
mPosition.value = progress.toLong()
|
||||
}
|
||||
|
||||
// Update the position and push the change the playbackManager.
|
||||
// This is done when the seek is confirmed to make playbackService seek to the position.
|
||||
fun updatePosition(progress: Int) {
|
||||
playbackManager.setPosition(progress.toLong())
|
||||
|
||||
playbackService.doSeek(progress.toLong())
|
||||
|
@ -136,14 +152,17 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
|
||||
// --- QUEUE FUNCTIONS ---
|
||||
|
||||
// Skip to next song.
|
||||
fun skipNext() {
|
||||
playbackManager.skipNext()
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
// Skip to last song.
|
||||
fun skipPrev() {
|
||||
playbackManager.skipPrev()
|
||||
playbackManager.prev()
|
||||
}
|
||||
|
||||
// Remove a queue item, given a QueueAdapter index.
|
||||
fun removeQueueItem(adapterIndex: Int) {
|
||||
// Translate the adapter indices into the correct queue indices
|
||||
val delta = mQueue.value!!.size - nextItemsInQueue.value!!.size
|
||||
|
@ -153,6 +172,7 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
playbackManager.removeQueueItem(index)
|
||||
}
|
||||
|
||||
// Move queue items, given QueueAdapter indices.
|
||||
fun moveQueueItems(adapterFrom: Int, adapterTo: Int) {
|
||||
// Translate the adapter indices into the correct queue indices
|
||||
val delta = mQueue.value!!.size - nextItemsInQueue.value!!.size
|
||||
|
@ -165,12 +185,14 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
|
||||
// --- STATUS FUNCTIONS ---
|
||||
|
||||
// Flip the playing status.
|
||||
fun invertPlayingStatus() {
|
||||
mCanAnimate = true
|
||||
|
||||
playbackManager.setPlayingStatus(!playbackManager.isPlaying)
|
||||
}
|
||||
|
||||
// Flip the shuffle status.
|
||||
fun invertShuffleStatus() {
|
||||
playbackManager.setShuffleStatus(!playbackManager.isShuffling)
|
||||
}
|
||||
|
@ -198,8 +220,10 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
|
|||
}
|
||||
|
||||
override fun onPositionUpdate(position: Long) {
|
||||
if (!mIsSeeking.value!!) {
|
||||
mPosition.value = position
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueueUpdate(queue: MutableList<Song>) {
|
||||
mQueue.value = queue
|
||||
|
|
|
@ -166,7 +166,7 @@ class PlaybackStateManager {
|
|||
|
||||
// --- QUEUE FUNCTIONS ---
|
||||
|
||||
fun skipNext() {
|
||||
fun next() {
|
||||
if (mIndex < mQueue.size) {
|
||||
mIndex = mIndex.inc()
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ class PlaybackStateManager {
|
|||
forceQueueUpdate()
|
||||
}
|
||||
|
||||
fun skipPrev() {
|
||||
fun prev() {
|
||||
if (mIndex > 0) {
|
||||
mIndex = mIndex.dec()
|
||||
}
|
||||
|
@ -215,6 +215,7 @@ class PlaybackStateManager {
|
|||
forceQueueUpdate()
|
||||
}
|
||||
|
||||
// Force any callbacks to update when the queue is changed.
|
||||
private fun forceQueueUpdate() {
|
||||
mQueue = mQueue
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue