Add seperate queue types
Add seperate queue types for different contexts, such as playing a song from an album.
This commit is contained in:
parent
96c30b3f93
commit
9f05ce6e52
7 changed files with 57 additions and 23 deletions
|
@ -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,
|
||||
|
|
|
@ -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 ---
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
10
app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt
Normal file
10
app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt
Normal 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
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue