From bc7950e7aff934e93cfc0df212c7410bb07ece1d Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sat, 7 Nov 2020 09:29:49 -0700 Subject: [PATCH] Make Queue nav destination Fix a heisenleak by making QueueFragment a navigation destination instead of being directly instantiated. --- .../oxycblt/auxio/playback/PlaybackFragment.kt | 11 +++++++++-- .../auxio/playback/PlaybackViewModel.kt | 15 +++++++++++++++ .../auxio/playback/queue/QueueFragment.kt | 18 ++++++++++++++---- .../playback/state/PlaybackStateManager.kt | 10 ++++++++-- app/src/main/res/layout/fragment_queue.xml | 1 - app/src/main/res/navigation/nav_main.xml | 11 ++++++++++- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/values/styles.xml | 2 +- 8 files changed, 59 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt index f363c14c8..c7fe578fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt @@ -15,7 +15,6 @@ import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackBinding -import org.oxycblt.auxio.playback.queue.QueueFragment import org.oxycblt.auxio.playback.state.LoopMode import org.oxycblt.auxio.theme.accent import org.oxycblt.auxio.theme.disable @@ -71,7 +70,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { setOnMenuItemClickListener { if (it.itemId == R.id.action_queue) { - QueueFragment().show(parentFragmentManager, "TAG_QUEUE") + findNavController().navigate(PlaybackFragmentDirections.actionShowQueue()) } true @@ -186,6 +185,14 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { queueMenuItem.isEnabled = true queueMenuItem.icon = iconQueueActive } + + // If someone edits the queue to make it have no songs left, then disable the + // skip next button. + if (playbackModel.index.value!! == it.size) { + binding.playbackSkipNext.disable(requireContext()) + } else { + binding.playbackSkipNext.enable(requireContext()) + } } Log.d(this::class.simpleName, "Fragment Created.") diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index acf63faee..103a57ff4 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.toDuration @@ -22,6 +23,9 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { private val mSong = MutableLiveData() val song: LiveData get() = mSong + private val mParent = MutableLiveData() + val parent: LiveData get() = mParent + private val mPosition = MutableLiveData(0L) val position: LiveData get() = mPosition @@ -32,6 +36,9 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { private val mIndex = MutableLiveData(0) val index: LiveData get() = mIndex + private val mMode = MutableLiveData(PlaybackMode.ALL_SONGS) + val mode: LiveData get() = mMode + // States private val mIsPlaying = MutableLiveData(false) val isPlaying: LiveData get() = mIsPlaying @@ -194,6 +201,10 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { mSong.value = song } + override fun onParentUpdate(parent: BaseModel?) { + mParent.value = parent + } + override fun onPositionUpdate(position: Long) { if (!mIsSeeking.value!!) { mPosition.value = position / 1000 @@ -208,6 +219,10 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { mIndex.value = index } + override fun onModeUpdate(mode: PlaybackMode) { + mMode.value = mode + } + override fun onPlayingUpdate(isPlaying: Boolean) { mIsPlaying.value = isPlaying } 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 397362b26..afe3b10ad 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 @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -12,6 +13,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentQueueBinding import org.oxycblt.auxio.playback.PlaybackViewModel +import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.theme.accent import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.toColor @@ -28,9 +30,7 @@ class QueueFragment : BottomSheetDialogFragment() { ): View? { val binding = FragmentQueueBinding.inflate(inflater) - val helper = ItemTouchHelper( - QueueDragCallback(playbackModel) - ) + val helper = ItemTouchHelper(QueueDragCallback(playbackModel)) val queueAdapter = QueueAdapter(helper) // --- UI SETUP --- @@ -47,9 +47,19 @@ class QueueFragment : BottomSheetDialogFragment() { // --- VIEWMODEL SETUP --- + playbackModel.mode.observe(viewLifecycleOwner) { + if (it == PlaybackMode.ALL_SONGS) { + binding.queueHeader.setText(R.string.label_next_songs) + } else { + binding.queueHeader.text = getString( + R.string.format_next_from, playbackModel.parent.value!!.name + ) + } + } + playbackModel.nextItemsInQueue.observe(viewLifecycleOwner) { if (it.isEmpty()) { - dismiss() + findNavController().navigateUp() return@observe } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 6b745a786..a30266273 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -29,6 +29,10 @@ class PlaybackStateManager private constructor() { callbacks.forEach { it.onPositionUpdate(value) } } private var mParent: BaseModel? = null + set(value) { + field = value + callbacks.forEach { it.onParentUpdate(value) } + } // Queue private var mQueue = mutableListOf() @@ -47,6 +51,7 @@ class PlaybackStateManager private constructor() { callbacks.forEach { it.onModeUpdate(value) } } + // Status private var mIsPlaying = false set(value) { field = value @@ -131,6 +136,7 @@ class PlaybackStateManager private constructor() { } fun playParentModel(baseModel: BaseModel, shuffled: Boolean) { + // This should never occur. if (baseModel is Song || baseModel is Header) { Log.e( this::class.simpleName, @@ -295,8 +301,7 @@ class PlaybackStateManager private constructor() { // If specified, make the current song the first member of the queue. if (keepSong) { mSong?.let { - mQueue.remove(it) - mQueue.add(0, it) + moveQueueItems(mQueue.indexOf(it), 0) } } else { // Otherwise, just start from the zeroth position in the queue. @@ -400,6 +405,7 @@ class PlaybackStateManager private constructor() { interface Callback { fun onSongUpdate(song: Song?) {} + fun onParentUpdate(parent: BaseModel?) {} fun onPositionUpdate(position: Long) {} fun onQueueUpdate(queue: MutableList) {} fun onModeUpdate(mode: PlaybackMode) {} diff --git a/app/src/main/res/layout/fragment_queue.xml b/app/src/main/res/layout/fragment_queue.xml index 7bc9ca717..fbc3bbf12 100644 --- a/app/src/main/res/layout/fragment_queue.xml +++ b/app/src/main/res/layout/fragment_queue.xml @@ -2,7 +2,6 @@ - + tools:layout="@layout/fragment_playback" > + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5c1d512f3..aadd0c25d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,6 +27,7 @@ Play Queue Add to queue + Next from: All Songs Music Playback The music playback service for Auxio. @@ -62,6 +63,7 @@ %1$s / %2$s %1$s / %2$s / %3$s %1$s, %2$s + Next From: %s %s Song diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 767d077e3..fa604bdb3 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -42,7 +42,7 @@