[Android] Refactor the PlaylistViewModel to listen to the item changes

Nicolas Pomepuy git at videolan.org
Fri Nov 18 12:29:45 UTC 2022


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Nov  3 11:04:19 2022 +0100| [1b3a45c365501b7fb1f20fbc2c3501cad0168f56] | committer: Nicolas Pomepuy

Refactor the PlaylistViewModel to listen to the item changes

> https://code.videolan.org/videolan/vlc-android/commit/1b3a45c365501b7fb1f20fbc2c3501cad0168f56
---

 .../videolan/vlc/gui/HeaderMediaListActivity.kt    | 59 ++++++++++++----------
 .../vlc/viewmodels/mobile/PlaylistViewModel.kt     | 33 ++++++++++--
 2 files changed, 61 insertions(+), 31 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/gui/HeaderMediaListActivity.kt b/application/vlc-android/src/org/videolan/vlc/gui/HeaderMediaListActivity.kt
index 4fba33ae6b..8fd7970834 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/HeaderMediaListActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/HeaderMediaListActivity.kt
@@ -123,14 +123,29 @@ open class HeaderMediaListActivity : AudioPlayerContainerActivity(), IEventsHand
             if (::itemTouchHelperCallback.isInitialized) itemTouchHelperCallback.swipeEnabled = true
         }
 
+        viewModel.playlistLiveData.observe(this) { playlist ->
+            (playlist as? Album)?.let {
+                binding.btnFavorite.setVisible()
+                binding.btnFavorite.setImageDrawable(ContextCompat.getDrawable(this, if (it.isFavorite) R.drawable.ic_header_media_favorite else R.drawable.ic_header_media_favorite_outline))
+            } ?: binding.btnFavorite.setGone()
+
+            var totalDuration = 0L
+            for (item in playlist.tracks)
+                totalDuration += item.length
+            binding.totalDuration = totalDuration
+
+            if (playlist is Album) {
+                val releaseYear = playlist.releaseYear
+                binding.releaseYear = if (releaseYear > 0) releaseYear.toString() else ""
+                if (releaseYear <= 0) binding.releaseDate.visibility = View.GONE
+            }
+        }
+
         viewModel.tracksProvider.liveHeaders.observe(this) {
             binding.songs.invalidateItemDecorations()
         }
         audioBrowserAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this, this, isPlaylist)
-        var totalDuration = 0L
-        for (item in viewModel.playlist.tracks)
-            totalDuration += item.length
-        binding.totalDuration = totalDuration
+
         if (isPlaylist) {
             audioBrowserAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this, this, isPlaylist)
             itemTouchHelperCallback = SwipeDragItemTouchHelperCallback(audioBrowserAdapter)
@@ -140,25 +155,18 @@ open class HeaderMediaListActivity : AudioPlayerContainerActivity(), IEventsHand
         } else {
             audioBrowserAdapter = AudioAlbumTracksAdapter(MediaLibraryItem.TYPE_MEDIA, this, this)
             binding.songs.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, viewModel.tracksProvider))
-            if (viewModel.playlist is Album) {
-                val releaseYear = (viewModel.playlist as Album).releaseYear
-                binding.releaseYear =  if (releaseYear > 0) releaseYear.toString() else ""
-                if (releaseYear <= 0) binding.releaseDate.visibility = View.GONE
-            }
+
         }
         binding.btnShuffle.setOnClickListener {
-            MediaUtils.playTracks(this, viewModel.playlist, SecureRandom().nextInt(min(playlist.tracksCount, MEDIALIBRARY_PAGE_SIZE)), true)
+            viewModel.playlist?.let { MediaUtils.playTracks(this, it, SecureRandom().nextInt(min(playlist.tracksCount, MEDIALIBRARY_PAGE_SIZE)), true) }
         }
         binding.btnAddPlaylist.setOnClickListener {
-            addToPlaylist(viewModel.playlist.tracks.toList())
+            viewModel.playlist?.let { addToPlaylist(it.tracks.toList()) }
         }
 
-        updateFavoriteState()
-
         binding.btnFavorite.setOnClickListener {
             lifecycleScope.launch {
                 viewModel.toggleFavorite()
-                updateFavoriteState()
             }
         }
 
@@ -200,20 +208,15 @@ open class HeaderMediaListActivity : AudioPlayerContainerActivity(), IEventsHand
         binding.playBtn.setOnClickListener(this)
     }
 
-    private fun updateFavoriteState() {
-        (viewModel.playlist as? Album)?.let {
-            binding.btnFavorite.setVisible()
-            binding.btnFavorite.setImageDrawable(ContextCompat.getDrawable(this, if (it.isFavorite) R.drawable.ic_header_media_favorite else R.drawable.ic_header_media_favorite_outline))
-        } ?: binding.btnFavorite.setGone()
-    }
-
     override fun onStop() {
         super.onStop()
         stopActionMode()
     }
 
     public override fun onSaveInstanceState(outState: Bundle) {
-        outState.putParcelable(AudioBrowserFragment.TAG_ITEM, viewModel.playlist)
+        viewModel.playlist?.let {
+            outState.putParcelable(AudioBrowserFragment.TAG_ITEM, it)
+        }
         super.onSaveInstanceState(outState)
     }
 
@@ -518,11 +521,13 @@ open class HeaderMediaListActivity : AudioPlayerContainerActivity(), IEventsHand
         itemTouchHelperCallback.swipeEnabled = false
         lifecycleScope.launchWhenStarted {
             val tracks = withContext(Dispatchers.IO) { playlist.tracks }
-            withContext(Dispatchers.IO) {
-                for ((index, playlistIndex) in indexes.sortedBy { it }.withIndex()) {
-                    val trueIndex = viewModel.playlist.tracks.indexOf(list[index])
-                    itemsRemoved[trueIndex] = tracks[playlistIndex].id
-                    playlist.remove(trueIndex)
+            viewModel.playlist?.let { playlist ->
+                withContext(Dispatchers.IO) {
+                    for ((index, playlistIndex) in indexes.sortedBy { it }.withIndex()) {
+                        val trueIndex = playlist.tracks.indexOf(list[index])
+                        itemsRemoved[trueIndex] = tracks[playlistIndex].id
+                        (playlist as Playlist).remove(trueIndex)
+                    }
                 }
             }
             var removedMessage = if (indexes.size>1) getString(R.string.removed_from_playlist_anonymous) else getString(R.string.remove_playlist_item,list.first().title)
diff --git a/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistViewModel.kt b/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistViewModel.kt
index 1d09431d7d..37eda77218 100644
--- a/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistViewModel.kt
+++ b/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistViewModel.kt
@@ -21,10 +21,12 @@
 package org.videolan.vlc.viewmodels.mobile
 
 import android.content.Context
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.videolan.medialibrary.interfaces.media.Album
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
@@ -35,13 +37,17 @@ import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
 import org.videolan.vlc.providers.medialibrary.TracksProvider
 import org.videolan.vlc.viewmodels.MedialibraryViewModel
 
-class PlaylistViewModel(context: Context, val playlist: MediaLibraryItem) : MedialibraryViewModel(context) {
+class PlaylistViewModel(context: Context, private val initialPlaylist: MediaLibraryItem) : MedialibraryViewModel(context) {
 
-    val tracksProvider = TracksProvider(playlist, context, this)
+    val tracksProvider = TracksProvider(initialPlaylist, context, this)
     override val providers : Array<MedialibraryProvider<out MediaLibraryItem>> = arrayOf(tracksProvider)
+    var playlistLiveData: MutableLiveData<MediaLibraryItem> = MutableLiveData()
+
+    val playlist:MediaLibraryItem?
+        get() = playlistLiveData.value
 
     init {
-        when (playlist) {
+        when (initialPlaylist) {
             is Playlist -> watchPlaylists()
             is Album -> {
                 watchAlbums()
@@ -50,6 +56,25 @@ class PlaylistViewModel(context: Context, val playlist: MediaLibraryItem) : Medi
             else -> watchMedia()
         }
         viewModelScope.registerCallBacks { refresh() }
+        viewModelScope.launch {
+            refreshPlaylistItem()
+        }
+    }
+
+    override fun refresh() {
+        viewModelScope.launch {
+            refreshPlaylistItem()
+            super.refresh()
+        }
+    }
+
+    private suspend fun refreshPlaylistItem() {
+        withContext(Dispatchers.IO) {
+            when (initialPlaylist) {
+                is Album -> playlistLiveData.postValue(medialibrary.getAlbum(initialPlaylist.id))
+                is Playlist -> playlistLiveData.postValue(medialibrary.getPlaylist(initialPlaylist.id, true))
+            }
+        }
     }
 
     class Factory(val context: Context, val playlist: MediaLibraryItem): ViewModelProvider.NewInstanceFactory() {
@@ -66,7 +91,7 @@ class PlaylistViewModel(context: Context, val playlist: MediaLibraryItem) : Medi
 
     suspend fun toggleFavorite() = withContext(Dispatchers.IO){
         when (playlist) {
-            is Album -> playlist.setFavorite(!playlist.isFavorite)
+            is Album -> (playlist as Album).setFavorite(!(playlist as Album).isFavorite)
             else ->{}
         }
     }



More information about the Android mailing list