feat: option to shuffle downloads in background

This commit is contained in:
Bnyro 2024-01-17 17:45:30 +01:00
parent efa35252d4
commit ed48f0ca49
5 changed files with 53 additions and 8 deletions

View File

@ -8,6 +8,7 @@ import androidx.core.content.getSystemService
import androidx.fragment.app.commit import androidx.fragment.app.commit
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.parcelable.PlayerData import com.github.libretube.parcelable.PlayerData
import com.github.libretube.services.OfflinePlayerService
import com.github.libretube.services.OnlinePlayerService import com.github.libretube.services.OnlinePlayerService
import com.github.libretube.ui.fragments.PlayerFragment import com.github.libretube.ui.fragments.PlayerFragment
@ -71,4 +72,18 @@ object BackgroundHelper {
return context.getSystemService<ActivityManager>()!!.getRunningServices(Int.MAX_VALUE) return context.getSystemService<ActivityManager>()!!.getRunningServices(Int.MAX_VALUE)
.any { serviceClass.name == it.service.className } .any { serviceClass.name == it.service.className }
} }
/**
* Start the offline background player
*
* @param context the current context
* @param videoId the videoId of the video or null if all available downloads should be shuffled
*/
fun playOnBackgroundOffline(context: Context, videoId: String?) {
val playerIntent = Intent(context, OfflinePlayerService::class.java)
.putExtra(IntentData.videoId, videoId)
context.stopService(playerIntent)
ContextCompat.startForegroundService(context, playerIntent)
}
} }

View File

@ -67,18 +67,30 @@ class OfflinePlayerService : LifecycleService() {
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
videoId = intent?.getStringExtra(IntentData.videoId)!!
lifecycleScope.launch { lifecycleScope.launch {
downloadsWithItems = withContext(Dispatchers.IO) { downloadsWithItems = withContext(Dispatchers.IO) {
DatabaseHolder.Database.downloadDao().getAll() DatabaseHolder.Database.downloadDao().getAll()
} }
val downloadWithItems = downloadsWithItems.first { it.download.videoId == videoId } if (downloadsWithItems.isEmpty()) {
onDestroy()
return@launch
}
val videoId = intent?.getStringExtra(IntentData.videoId)
val downloadToPlay = if (videoId == null) {
downloadsWithItems = downloadsWithItems.shuffled()
downloadsWithItems.first()
} else {
downloadsWithItems.first { it.download.videoId == videoId }
}
this@OfflinePlayerService.videoId = downloadToPlay.download.videoId
createPlayerAndNotification() createPlayerAndNotification()
// destroy the service if there was no success playing the selected audio/video // destroy the service if there was no success playing the selected audio/video
if (!startAudioPlayer(downloadWithItems)) onDestroy() if (!startAudioPlayer(downloadToPlay)) onDestroy()
} }
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)

View File

@ -9,6 +9,7 @@ import android.os.IBinder
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -16,15 +17,18 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.FragmentDownloadsBinding import com.github.libretube.databinding.FragmentDownloadsBinding
import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.DownloadWithItems import com.github.libretube.db.obj.DownloadWithItems
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.helpers.BackgroundHelper
import com.github.libretube.helpers.DownloadHelper import com.github.libretube.helpers.DownloadHelper
import com.github.libretube.obj.DownloadStatus import com.github.libretube.obj.DownloadStatus
import com.github.libretube.receivers.DownloadReceiver import com.github.libretube.receivers.DownloadReceiver
import com.github.libretube.services.DownloadService import com.github.libretube.services.DownloadService
import com.github.libretube.services.OfflinePlayerService
import com.github.libretube.ui.adapters.DownloadsAdapter import com.github.libretube.ui.adapters.DownloadsAdapter
import com.github.libretube.ui.base.DynamicLayoutManagerFragment import com.github.libretube.ui.base.DynamicLayoutManagerFragment
import com.github.libretube.ui.viewholders.DownloadsViewHolder import com.github.libretube.ui.viewholders.DownloadsViewHolder
@ -150,6 +154,10 @@ class DownloadsFragment : DynamicLayoutManagerFragment() {
} }
} }
) )
binding.shuffleBackground.setOnClickListener {
BackgroundHelper.playOnBackgroundOffline(requireContext(), null)
}
} }
override fun onStart() { override fun onStart() {

View File

@ -8,6 +8,7 @@ import androidx.fragment.app.setFragmentResult
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.enums.ShareObjectType import com.github.libretube.enums.ShareObjectType
import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.NavigationHelper import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.obj.ShareData import com.github.libretube.obj.ShareData
import com.github.libretube.services.OfflinePlayerService import com.github.libretube.services.OfflinePlayerService
@ -27,10 +28,7 @@ class DownloadOptionsBottomSheet : BaseBottomSheet() {
setSimpleItems(options.map { getString(it) }) { which -> setSimpleItems(options.map { getString(it) }) { which ->
when (options[which]) { when (options[which]) {
R.string.playOnBackground -> { R.string.playOnBackground -> {
val playerIntent = Intent(requireContext(), OfflinePlayerService::class.java) BackgroundHelper.playOnBackgroundOffline(requireContext(), videoId)
.putExtra(IntentData.videoId, videoId)
context?.stopService(playerIntent)
ContextCompat.startForegroundService(requireContext(), playerIntent)
} }
R.string.go_to_video -> { R.string.go_to_video -> {

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:attr/colorBackground"> android:background="?android:attr/colorBackground">
@ -33,4 +34,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" /> android:visibility="gone" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/shuffle_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/shuffle"
android:src="@drawable/ic_shuffle"
android:tooltipText="@string/shuffle"
tools:targetApi="o" />
</FrameLayout> </FrameLayout>