diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 6be7cd419..5b09909cf 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -22,6 +22,7 @@ class AlbumDetailFragment : Fragment() { private val args: AlbumDetailFragmentArgs by navArgs() private val detailModel: DetailViewModel by activityViewModels() private val playbackModel: PlaybackViewModel by activityViewModels() + private val musicModel: MusicViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, @@ -45,7 +46,7 @@ class AlbumDetailFragment : Fragment() { } val songAdapter = DetailSongAdapter { - playbackModel.updateSong(it) + playbackModel.update(it, musicModel.songs.value!!) } // --- UI SETUP --- diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index 652091c5f..06b0f8260 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -190,7 +190,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.updateSong(baseModel) + playbackModel.update(baseModel, musicModel.songs.value!!) return } diff --git a/app/src/main/java/org/oxycblt/auxio/music/Models.kt b/app/src/main/java/org/oxycblt/auxio/music/Models.kt index d7cb419c0..be8c8447c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -67,6 +67,22 @@ data class Artist( } return num } + val songs: MutableList + get() { + val songs = mutableListOf() + albums.forEach { + songs.addAll(it.songs) + } + return songs + } + val genreSongs: MutableList + get() { + val songs = mutableListOf() + genres.forEach { + songs.addAll(it.songs) + } + return songs + } } // Genre @@ -93,6 +109,14 @@ data class Genre( } return num } + val songs: MutableList + get() { + val songs = mutableListOf() + artists.forEach { + songs.addAll(it.songs) + } + return songs + } } // Header [Used for search, nothing else] 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 532d24218..ff8d9f98b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt @@ -15,6 +15,8 @@ import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackBinding import org.oxycblt.auxio.theme.accent +import org.oxycblt.auxio.theme.disable +import org.oxycblt.auxio.theme.enable import org.oxycblt.auxio.theme.toColor class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { @@ -33,8 +35,11 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { // Create accents & icons to use val accentColor = ColorStateList.valueOf(accent.first.toColor(requireContext())) - val inactiveColor = ColorStateList.valueOf(R.color.control_color.toColor(requireContext())) + val controlColor = ColorStateList.valueOf(R.color.control_color.toColor(requireContext())) val normalTextColor = binding.playbackDurationCurrent.currentTextColor + val disabledColor = ColorStateList.valueOf( + R.color.inactive_color.toColor(requireContext()) + ) val iconPauseToPlay = ContextCompat.getDrawable( requireContext(), R.drawable.ic_pause_to_play @@ -60,10 +65,29 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { // --- VIEWMODEL SETUP -- playbackModel.currentSong.observe(viewLifecycleOwner) { + Log.d(this::class.simpleName, "Updating song display to ${it.name}.") + binding.song = it binding.playbackSeekBar.max = it.seconds.toInt() } + playbackModel.currentIndex.observe(viewLifecycleOwner) { + if (it > 0) { + binding.playbackSkipPrev.enable(requireContext()) + } else { + binding.playbackSkipPrev.disable(requireContext()) + } + + Log.d(this::class.simpleName, it.toString()) + + if (it < playbackModel.queue.value!!.lastIndex) { + binding.playbackSkipNext.enable(requireContext()) + } else { + Log.d(this::class.simpleName, "Fucking stupid retard.") + binding.playbackSkipNext.disable(requireContext()) + } + } + playbackModel.isPlaying.observe(viewLifecycleOwner) { if (it) { // Animate the playing status and switch the button to the accent color @@ -76,7 +100,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener { binding.playbackPlayPause.setImageDrawable(iconPlayToPause) iconPlayToPause.start() - binding.playbackPlayPause.backgroundTintList = inactiveColor + binding.playbackPlayPause.backgroundTintList = controlColor } } 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 b3fc35b73..9f583e09e 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -15,6 +15,12 @@ class PlaybackViewModel : ViewModel() { private val mCurrentSong = MutableLiveData() val currentSong: LiveData get() = mCurrentSong + private val mCurrentIndex = MutableLiveData(0) + val currentIndex: LiveData get() = mCurrentIndex + + private val mQueue = MutableLiveData(mutableListOf()) + val queue: LiveData> get() = mQueue + private val mCurrentDuration = MutableLiveData(0L) val currentDuration: LiveData get() = mCurrentDuration @@ -33,7 +39,15 @@ class PlaybackViewModel : ViewModel() { if (mCurrentSong.value != null) it.toInt() else 0 } - fun updateSong(song: Song) { + // Update the current song while changing the queue to All Songs. + fun update(song: Song, allSongs: List) { + updatePlayback(song) + + mQueue.value = allSongs.toMutableList() + mCurrentIndex.value = allSongs.indexOf(song) + } + + private fun updatePlayback(song: Song) { mCurrentSong.value = song mCurrentDuration.value = 0 @@ -56,4 +70,20 @@ class PlaybackViewModel : ViewModel() { fun updateCurrentDurationWithProgress(progress: Int) { mCurrentDuration.value = progress.toLong() } + + fun skipNext() { + if (mCurrentIndex.value!! < mQueue.value!!.size) { + mCurrentIndex.value = mCurrentIndex.value!!.inc() + } + + updatePlayback(mQueue.value!![mCurrentIndex.value!!]) + } + + fun skipPrev() { + if (mCurrentIndex.value!! > 0) { + mCurrentIndex.value = mCurrentIndex.value!!.dec() + } + + updatePlayback(mQueue.value!![mCurrentIndex.value!!]) + } } diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt b/app/src/main/java/org/oxycblt/auxio/recycler/DiffCallback.kt similarity index 100% rename from app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt rename to app/src/main/java/org/oxycblt/auxio/recycler/DiffCallback.kt diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt index ae3a3ba25..598aa1b75 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -33,7 +33,7 @@ class SongsFragment : Fragment() { binding.songRecycler.apply { adapter = SongAdapter(musicModel.songs.value!!) { - playbackModel.updateSong(it) + playbackModel.update(it, musicModel.songs.value!!) } applyDivider() setHasFixedSize(true) diff --git a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt index 592d0586f..b8dc00884 100644 --- a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt @@ -103,6 +103,16 @@ fun ImageButton.disable(context: Context) { isEnabled = false } +fun ImageButton.enable(context: Context) { + if (!isEnabled) { + imageTintList = ColorStateList.valueOf( + R.color.control_color.toColor(context) + ) + + isEnabled = true + } +} + // Apply a custom vertical divider fun RecyclerView.applyDivider() { val div = DividerItemDecoration( diff --git a/app/src/main/res/drawable/ic_down.xml b/app/src/main/res/drawable/ic_down.xml index 570a79901..00758a13a 100644 --- a/app/src/main/res/drawable/ic_down.xml +++ b/app/src/main/res/drawable/ic_down.xml @@ -7,5 +7,5 @@ android:tint="@color/control_color"> + android:pathData="M 5.88,7.06 12,13.166667 18.12,7.06 20,8.94 l -8,8 -8,-8 z" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_skip_next.xml b/app/src/main/res/drawable/ic_skip_next.xml new file mode 100644 index 000000000..a8ca69293 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_next.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_skip_prev.xml b/app/src/main/res/drawable/ic_skip_prev.xml new file mode 100644 index 000000000..f69d615a0 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_prev.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_playback.xml b/app/src/main/res/layout/fragment_playback.xml index 8c98e4678..c1663bfa2 100644 --- a/app/src/main/res/layout/fragment_playback.xml +++ b/app/src/main/res/layout/fragment_playback.xml @@ -19,6 +19,7 @@ android:id="@+id/playback_layout" android:layout_width="match_parent" android:layout_height="match_parent" + android:animateLayoutChanges="true" android:background="@color/background"> + + + + \ 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 1d6258741..c34c0365c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,6 +39,8 @@ Sort from Z to A Play Pause + Skip to next song + Skip to last song Unknown Genre