feat: support for shuffling downloaded audio content

This commit is contained in:
Bnyro 2024-10-15 12:11:06 +02:00
parent 84eea3df56
commit c16764fbfb
5 changed files with 65 additions and 14 deletions

View File

@ -50,4 +50,5 @@ object IntentData {
const val videoInfo = "videoInfo" const val videoInfo = "videoInfo"
const val offlinePlayer = "offlinePlayer" const val offlinePlayer = "offlinePlayer"
const val downloadTab = "downloadTab" const val downloadTab = "downloadTab"
const val shuffle = "shuffle"
} }

View File

@ -77,11 +77,12 @@ object BackgroundHelper {
* @param context the current context * @param context the current context
* @param videoId the videoId of the video or null if all available downloads should be shuffled * @param videoId the videoId of the video or null if all available downloads should be shuffled
*/ */
fun playOnBackgroundOffline(context: Context, videoId: String?, downloadTab: DownloadTab) { fun playOnBackgroundOffline(context: Context, videoId: String?, downloadTab: DownloadTab, shuffle: Boolean = false) {
stopBackgroundPlay(context) stopBackgroundPlay(context)
val playerIntent = Intent(context, OfflinePlayerService::class.java) val playerIntent = Intent(context, OfflinePlayerService::class.java)
.putExtra(IntentData.videoId, videoId) .putExtra(IntentData.videoId, videoId)
.putExtra(IntentData.shuffle, shuffle)
.putExtra(IntentData.downloadTab, downloadTab) .putExtra(IntentData.downloadTab, downloadTab)
ContextCompat.startForegroundService(context, playerIntent) ContextCompat.startForegroundService(context, playerIntent)

View File

@ -21,6 +21,7 @@ import com.github.libretube.ui.fragments.DownloadTab
import com.github.libretube.util.PlayingQueue import com.github.libretube.util.PlayingQueue
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlin.io.path.exists import kotlin.io.path.exists
@ -31,10 +32,20 @@ import kotlin.io.path.exists
class OfflinePlayerService : AbstractPlayerService() { class OfflinePlayerService : AbstractPlayerService() {
private var downloadWithItems: DownloadWithItems? = null private var downloadWithItems: DownloadWithItems? = null
private lateinit var downloadTab: DownloadTab private lateinit var downloadTab: DownloadTab
private var shuffle: Boolean = false
override suspend fun onServiceCreated(intent: Intent) { override suspend fun onServiceCreated(intent: Intent) {
videoId = intent.getStringExtra(IntentData.videoId) ?: return
downloadTab = intent.serializableExtra(IntentData.downloadTab)!! downloadTab = intent.serializableExtra(IntentData.downloadTab)!!
shuffle = intent.getBooleanExtra(IntentData.shuffle, false)
videoId = if (shuffle) {
runBlocking(Dispatchers.IO) {
Database.downloadDao().getAll().filterByTab(downloadTab)
.randomOrNull()?.download?.videoId
}
} else {
intent.getStringExtra(IntentData.videoId)
} ?: return
PlayingQueue.clear() PlayingQueue.clear()
@ -92,7 +103,11 @@ class OfflinePlayerService : AbstractPlayerService() {
private suspend fun fillQueue() { private suspend fun fillQueue() {
val downloads = withContext(Dispatchers.IO) { val downloads = withContext(Dispatchers.IO) {
Database.downloadDao().getAll() Database.downloadDao().getAll()
}.filterByTab(downloadTab) }
.filterByTab(downloadTab)
.toMutableList()
if (shuffle) downloads.shuffle()
PlayingQueue.insertRelatedStreams(downloads.map { it.download.toStreamItem() }) PlayingQueue.insertRelatedStreams(downloads.map { it.download.toStreamItem() })
} }

View File

@ -31,7 +31,9 @@ import com.github.libretube.db.obj.filterByTab
import com.github.libretube.extensions.ceilHalf import com.github.libretube.extensions.ceilHalf
import com.github.libretube.extensions.formatAsFileSize import com.github.libretube.extensions.formatAsFileSize
import com.github.libretube.extensions.serializable import com.github.libretube.extensions.serializable
import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.DownloadHelper import com.github.libretube.helpers.DownloadHelper
import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.helpers.PreferenceHelper import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.obj.DownloadStatus import com.github.libretube.obj.DownloadStatus
import com.github.libretube.receivers.DownloadReceiver import com.github.libretube.receivers.DownloadReceiver
@ -253,6 +255,17 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment() {
binding.deleteAll.setOnClickListener { binding.deleteAll.setOnClickListener {
showDeleteAllDialog(binding.root.context, adapter) showDeleteAllDialog(binding.root.context, adapter)
} }
binding.shuffleAll.setOnClickListener {
BackgroundHelper.playOnBackgroundOffline(
requireContext(),
null,
downloadTab,
shuffle = true
)
NavigationHelper.startAudioPlayer(requireContext(), offlinePlayer = true)
}
} }
private fun toggleVisibilities() { private fun toggleVisibilities() {
@ -262,6 +275,7 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment() {
binding.downloadsEmpty.isVisible = isEmpty binding.downloadsEmpty.isVisible = isEmpty
binding.downloadsContainer.isGone = isEmpty binding.downloadsContainer.isGone = isEmpty
binding.deleteAll.isGone = isEmpty binding.deleteAll.isGone = isEmpty
binding.shuffleAll.isGone = isEmpty || downloadTab != DownloadTab.AUDIO
} }
private fun sortDownloadList(sortType: Int, previousSortType: Int? = null) { private fun sortDownloadList(sortType: Int, previousSortType: Int? = null) {

View File

@ -60,20 +60,40 @@
android:textStyle="bold" /> android:textStyle="bold" />
</LinearLayout> </LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton <LinearLayout
android:id="@+id/delete_all"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="18dp"
android:layout_marginBottom="18dp"
android:contentDescription="@string/delete_all"
android:src="@drawable/ic_delete"
android:tooltipText="@string/delete"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
tools:targetApi="o" android:layout_marginEnd="18dp"
tools:visibility="visible" /> android:layout_marginBottom="18dp"
android:orientation="vertical">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/delete_all"
style="?attr/floatingActionButtonSmallSecondaryStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:contentDescription="@string/delete_all"
android:src="@drawable/ic_delete"
android:tooltipText="@string/delete"
android:visibility="gone"
tools:targetApi="o"
tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/shuffle_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/shuffle"
android:src="@drawable/ic_shuffle"
android:layout_marginTop="8dp"
android:tooltipText="@string/shuffle"
android:visibility="gone"
tools:targetApi="o"
tools:visibility="visible" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>