[Android] Fix shuffle issues in the file browser

Nicolas Pomepuy git at videolan.org
Fri Aug 8 08:40:13 UTC 2025


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Fri Jul 25 12:05:40 2025 +0200| [c707384d99b93492e7cf95ed12eabe87c6b625fc] | committer: Duncan McNamara

Fix shuffle issues in the file browser

Fixes #3227

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

 .../org/videolan/vlc/gui/browser/BaseBrowserFragment.kt   | 15 ++++++++++++---
 .../vlc-android/src/org/videolan/vlc/media/MediaUtils.kt  |  4 +++-
 .../src/org/videolan/vlc/media/PlaylistManager.kt         |  9 ++++++++-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
index 1fc77bb316..653c25ec28 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
@@ -307,6 +307,11 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
                 viewModel.refresh()
             }
         }
+        lifecycleScope.launch {
+            PlaylistManager.shuffling.collect {
+                setupFab()
+            }
+        }
     }
 
     override fun onDisplaySettingChanged(key: String, value: Any) {
@@ -397,12 +402,16 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
             it?.addCallback(this)
         }.launchIn(startedScope)
 
+        setupFab()
+        (activity as? AudioPlayerContainerActivity)?.expandAppBar()
+    }
+
+    private fun setupFab() {
         fabPlay?.run {
-            setImageResource(R.drawable.ic_fab_play)
+            setImageResource(if (PlaylistManager.shuffling.value) R.drawable.ic_fab_shuffle else R.drawable.ic_fab_play)
             updateFab()
             fabPlay?.contentDescription = getString(R.string.play)
         }
-        (activity as? AudioPlayerContainerActivity)?.expandAppBar()
     }
 
 
@@ -579,7 +588,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
                     }
             }
             scheduler.startAction(MSG_HIDE_ENQUEUING)
-            activity?.let { MediaUtils.openList(it, mediaLocations, positionInPlaylist) }
+            activity?.let { MediaUtils.openList(it, mediaLocations, positionInPlaylist, shuffle = PlaylistManager.shuffling.value) }
         }
     }
 
diff --git a/application/vlc-android/src/org/videolan/vlc/media/MediaUtils.kt b/application/vlc-android/src/org/videolan/vlc/media/MediaUtils.kt
index 8a792afb2d..f3c8a8131d 100644
--- a/application/vlc-android/src/org/videolan/vlc/media/MediaUtils.kt
+++ b/application/vlc-android/src/org/videolan/vlc/media/MediaUtils.kt
@@ -294,7 +294,9 @@ object MediaUtils {
     fun openList(context: Context?, list: List<MediaWrapper>, position: Int, shuffle: Boolean = false) {
         if (list.isEmpty() || context == null) return
         SuspendDialogCallback(context) { service ->
-            service.load(list, position)
+            val realPos = if (shuffle) SecureRandom().nextInt(list.size)
+            else position
+            service.load(list, realPos)
             if (shuffle && !service.isShuffling) service.shuffle()
         }
     }
diff --git a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
index 07ffc7aa89..f951627c89 100644
--- a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
+++ b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
@@ -122,6 +122,7 @@ class PlaylistManager(val service: PlaybackService) : MediaWrapperList.EventList
         private val mediaList = MediaWrapperList()
         fun hasMedia() = mediaList.size() != 0
         val repeating = MutableStateFlow(PlaybackStateCompat.REPEAT_MODE_NONE)
+        val shuffling = MutableStateFlow(false)
         var playingAsAudio = false
     }
 
@@ -138,7 +139,13 @@ class PlaylistManager(val service: PlaybackService) : MediaWrapperList.EventList
     private var prevIndex = -1
     private var previous = Stack<Int>()
     var stopAfter = -1
-    var shuffling = false
+    var shuffling: Boolean = false
+        set(value) {
+            field = value
+            AppScope.launch {
+                PlaylistManager.shuffling.emit(value)
+            }
+        }
     var videoBackground = false
         private set
     var isBenchmark = false



More information about the Android mailing list