Add seperate queue types

Add seperate queue types for different contexts, such as playing a song from an album.
This commit is contained in:
OxygenCobalt 2020-10-14 08:09:45 -06:00
parent 96c30b3f93
commit 9f05ce6e52
7 changed files with 57 additions and 23 deletions

View file

@ -7,14 +7,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import org.oxycblt.auxio.databinding.FragmentMainBinding
import org.oxycblt.auxio.library.LibraryFragment
import org.oxycblt.auxio.loading.LoadingViewModel
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.songs.SongsFragment
import org.oxycblt.auxio.theme.accent
@ -23,10 +21,6 @@ import org.oxycblt.auxio.theme.getTransparentAccent
import org.oxycblt.auxio.theme.toColor
class MainFragment : Fragment() {
private val loadingModel: LoadingViewModel by activityViewModels {
LoadingViewModel.Factory(requireActivity().application)
}
private val shownFragments = listOf(0, 1)
private val tabIcons = listOf(
R.drawable.ic_library,

View file

@ -13,6 +13,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.disable
@ -44,7 +45,7 @@ class AlbumDetailFragment : Fragment() {
}
val songAdapter = DetailSongAdapter {
playbackModel.update(it)
playbackModel.update(it, PlaybackMode.IN_ALBUM)
}
// --- UI SETUP ---

View file

@ -25,6 +25,7 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.theme.applyColor
import org.oxycblt.auxio.theme.applyDivider
@ -181,7 +182,7 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
// If the item is a song [That was selected through search], then update the playback
// to that song instead of doing any navigation
if (baseModel is Song) {
playbackModel.update(baseModel)
playbackModel.update(baseModel, PlaybackMode.ALL_SONGS)
return
}

View file

@ -0,0 +1,10 @@
package org.oxycblt.auxio.playback
// Enum for instruction how the queue should function.
// ALL SONGS -> Play from all songs
// IN_GENRE -> Play from the genre
// IN_ARTIST -> Play from the songs of the artist
// IN_ALBUM -> Play from the songs of the album
enum class PlaybackMode {
ALL_SONGS, IN_GENRE, IN_ARTIST, IN_ALBUM
}

View file

@ -1,5 +1,6 @@
package org.oxycblt.auxio.playback
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
@ -9,6 +10,7 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.toDuration
// TODO: Implement media controls
// TODO: Implement persistence
// TODO: Add the playback service itself
// TODO: Possibly add some swipe-to-next-track function, could require a ViewPager.
// A ViewModel that acts as an intermediary between PlaybackService and the Playback Fragments.
@ -16,14 +18,15 @@ class PlaybackViewModel : ViewModel() {
private val mCurrentSong = MutableLiveData<Song>()
val currentSong: LiveData<Song> get() = mCurrentSong
private val mCurrentIndex = MutableLiveData(0)
val currentIndex: LiveData<Int> get() = mCurrentIndex
private val mQueue = MutableLiveData(mutableListOf<Song>())
val queue: LiveData<MutableList<Song>> get() = mQueue
private val mCurrentIndex = MutableLiveData(0)
val currentIndex: LiveData<Int> get() = mCurrentIndex
private val mCurrentMode = MutableLiveData(PlaybackMode.ALL_SONGS)
private val mCurrentDuration = MutableLiveData(0L)
val currentDuration: LiveData<Long> get() = mCurrentDuration
private val mIsPlaying = MutableLiveData(false)
val isPlaying: LiveData<Boolean> get() = mIsPlaying
@ -32,22 +35,43 @@ class PlaybackViewModel : ViewModel() {
val isSeeking: LiveData<Boolean> get() = mIsSeeking
// Formatted variants of the duration
val formattedCurrentDuration = Transformations.map(currentDuration) {
val formattedCurrentDuration = Transformations.map(mCurrentDuration) {
it.toDuration()
}
val formattedSeekBarProgress = Transformations.map(currentDuration) {
val formattedSeekBarProgress = Transformations.map(mCurrentDuration) {
if (mCurrentSong.value != null) it.toInt() else 0
}
// Update the current song while changing the queue to All Songs.
fun update(song: Song) {
// Update the current song while changing the queue mode.
fun update(song: Song, mode: PlaybackMode) {
Log.d(this::class.simpleName, "Updating song to ${song.name} and mode to $mode")
val musicStore = MusicStore.getInstance()
updatePlayback(song)
mQueue.value = musicStore.songs.toMutableList()
mCurrentIndex.value = musicStore.songs.indexOf(song)
mQueue.value = when (mode) {
PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList()
PlaybackMode.IN_ARTIST -> song.album.artist.songs
PlaybackMode.IN_ALBUM -> song.album.songs
// Warning: Calling update() with a mode of IN_GENRE Will cause Auxio to play
// from the artist's most prominent genre instead of the song's genre.
// FIXME: This could be fixed by moving genre loading to songs
PlaybackMode.IN_GENRE -> {
Log.d(
this::class.simpleName,
"update() was called with IN_GENRES, using " +
"most prominent genre instead of the song's genre."
)
song.album.artist.genres[0].songs
}
}
mCurrentMode.value = mode
mCurrentIndex.value = mQueue.value!!.indexOf(song)
}
private fun updatePlayback(song: Song) {

View file

@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import org.oxycblt.auxio.databinding.FragmentSongsBinding
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.theme.applyDivider
@ -31,7 +32,7 @@ class SongsFragment : Fragment() {
binding.songRecycler.apply {
adapter = SongAdapter(musicStore.songs) {
playbackModel.update(it)
playbackModel.update(it, PlaybackMode.ALL_SONGS)
}
applyDivider()
setHasFixedSize(true)

View file

@ -96,13 +96,16 @@ fun MenuItem.applyColor(@ColorInt color: Int) {
// Disable an ImageButton
fun ImageButton.disable(context: Context) {
imageTintList = ColorStateList.valueOf(
R.color.inactive_color.toColor(context)
)
if (isEnabled) {
imageTintList = ColorStateList.valueOf(
R.color.inactive_color.toColor(context)
)
isEnabled = false
isEnabled = false
}
}
// Enable an ImageButton
fun ImageButton.enable(context: Context) {
if (!isEnabled) {
imageTintList = ColorStateList.valueOf(