From 4441a2bf4e65f3f873513ea94b2c7a5be21cc513 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 19 Nov 2024 13:59:35 +0100 Subject: [PATCH] refactor: simplify playing queue listener handling --- .../libretube/extensions/MediaController.kt | 16 +++++++++ .../services/AbstractPlayerService.kt | 18 ++++++---- .../services/OfflinePlayerService.kt | 5 --- .../libretube/services/OnlinePlayerService.kt | 5 --- .../ui/adapters/PlayingQueueAdapter.kt | 11 +++++-- .../ui/fragments/AudioPlayerFragment.kt | 8 +++-- .../libretube/ui/sheets/PlayingQueueSheet.kt | 11 ++++++- .../libretube/ui/views/CustomExoPlayerView.kt | 19 ++++++++--- .../com/github/libretube/util/PlayingQueue.kt | 33 ------------------- 9 files changed, 66 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/extensions/MediaController.kt diff --git a/app/src/main/java/com/github/libretube/extensions/MediaController.kt b/app/src/main/java/com/github/libretube/extensions/MediaController.kt new file mode 100644 index 000000000..d8c5f9d60 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/MediaController.kt @@ -0,0 +1,16 @@ +package com.github.libretube.extensions + +import androidx.annotation.OptIn +import androidx.core.os.bundleOf +import androidx.media3.common.util.UnstableApi +import androidx.media3.session.MediaController +import com.github.libretube.enums.PlayerCommand +import com.github.libretube.services.AbstractPlayerService + +@OptIn(UnstableApi::class) +fun MediaController.navigateVideo(videoId: String) { + sendCustomCommand( + AbstractPlayerService.runPlayerActionCommand, + bundleOf(PlayerCommand.PLAY_VIDEO_BY_ID.name to videoId) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/github/libretube/services/AbstractPlayerService.kt b/app/src/main/java/com/github/libretube/services/AbstractPlayerService.kt index 2b4c37a55..fdfc3623c 100644 --- a/app/src/main/java/com/github/libretube/services/AbstractPlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/AbstractPlayerService.kt @@ -158,15 +158,19 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio } args.containsKey(PlayerCommand.PLAY_VIDEO_BY_ID.name) -> { - videoId = args.getString(PlayerCommand.PLAY_VIDEO_BY_ID.name) ?: return - - CoroutineScope(Dispatchers.IO).launch { - startPlayback() - } + navigateVideo(args.getString(PlayerCommand.PLAY_VIDEO_BY_ID.name) ?: return) } } } + private fun navigateVideo(videoId: String) { + this.videoId = videoId + + CoroutineScope(Dispatchers.IO).launch { + startPlayback() + } + } + fun getSubtitleRoleFlags(subtitle: Subtitle?): Int { return if (subtitle?.autoGenerated != true) { C.ROLE_FLAG_CAPTION @@ -180,11 +184,11 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio when (event) { PlayerEvent.Next -> { - PlayingQueue.navigateNext() + navigateVideo(PlayingQueue.getNext() ?: return) } PlayerEvent.Prev -> { - PlayingQueue.navigatePrev() + navigateVideo(PlayingQueue.getPrev() ?: return) } PlayerEvent.Stop -> { diff --git a/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt index 4b42ba8e1..f94db6549 100644 --- a/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt @@ -14,7 +14,6 @@ import com.github.libretube.enums.FileType import com.github.libretube.extensions.serializable import com.github.libretube.extensions.setMetadata import com.github.libretube.extensions.toAndroidUri -import com.github.libretube.extensions.toID import com.github.libretube.helpers.PlayerHelper import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.activities.NoInternetActivity @@ -67,10 +66,6 @@ open class OfflinePlayerService : AbstractPlayerService() { PlayingQueue.clear() - PlayingQueue.setOnQueueTapListener { streamItem -> - streamItem.url?.toID()?.let { playNextVideo(it) } - } - exoPlayer?.addListener(playerListener) fillQueue() diff --git a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt index 901ae93bd..5aacd5aea 100644 --- a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt @@ -24,7 +24,6 @@ import com.github.libretube.db.DatabaseHelper import com.github.libretube.enums.PlayerCommand import com.github.libretube.extensions.parcelable import com.github.libretube.extensions.setMetadata -import com.github.libretube.extensions.toID import com.github.libretube.extensions.toastFromMainDispatcher import com.github.libretube.extensions.toastFromMainThread import com.github.libretube.helpers.PlayerHelper @@ -113,10 +112,6 @@ open class OnlinePlayerService : AbstractPlayerService() { if (!playerData.keepQueue) PlayingQueue.clear() - PlayingQueue.setOnQueueTapListener { streamItem -> - streamItem.url?.toID()?.let { playNextVideo(it) } - } - exoPlayer?.addListener(playerListener) } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt index 4a38cd38f..7fdcd01b2 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt @@ -13,7 +13,9 @@ import com.github.libretube.helpers.ThemeHelper import com.github.libretube.ui.viewholders.PlayingQueueViewHolder import com.github.libretube.util.PlayingQueue -class PlayingQueueAdapter : RecyclerView.Adapter() { +class PlayingQueueAdapter( + private val onQueueItemSelected: (String) -> Unit +) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlayingQueueViewHolder { val binding = QueueRowBinding.inflate( @@ -45,14 +47,17 @@ class PlayingQueueAdapter : RecyclerView.Adapter() { ) root.setOnClickListener { + val newVideoId = streamItem.url?.toID() ?: return@setOnClickListener + val oldPosition = PlayingQueue.currentIndex() // get the new position from the queue to work properly after reordering the queue val newPosition = PlayingQueue.getStreams().indexOfFirst { - it.url?.toID() == streamItem.url?.toID() + it.url?.toID() == newVideoId }.takeIf { it >= 0 } ?: return@setOnClickListener + PlayingQueue.updateCurrent(streamItem) // select the new item in the queue and update the selected item in the UI - PlayingQueue.onQueueItemSelected(newPosition) + onQueueItemSelected(newVideoId) notifyItemChanged(oldPosition) notifyItemChanged(newPosition) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt index ab0e87086..ec37ea673 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt @@ -27,6 +27,7 @@ import com.github.libretube.R import com.github.libretube.api.obj.ChapterSegment import com.github.libretube.constants.IntentData import com.github.libretube.databinding.FragmentAudioPlayerBinding +import com.github.libretube.extensions.navigateVideo import com.github.libretube.extensions.normalize import com.github.libretube.extensions.parcelableList import com.github.libretube.extensions.seekBy @@ -143,11 +144,11 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions { } binding.prev.setOnClickListener { - PlayingQueue.navigatePrev() + playerController?.navigateVideo(PlayingQueue.getPrev() ?: return@setOnClickListener) } binding.next.setOnClickListener { - PlayingQueue.navigateNext() + playerController?.navigateVideo(PlayingQueue.getNext() ?: return@setOnClickListener) } listOf(binding.forwardTV, binding.rewindTV).forEach { @@ -160,6 +161,9 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions { playerController?.seekBy(PlayerHelper.seekIncrement) } + childFragmentManager.setFragmentResultListener(PlayingQueueSheet.PLAYING_QUEUE_REQUEST_KEY, viewLifecycleOwner) { _, args -> + playerController?.navigateVideo(args.getString(IntentData.videoId) ?: return@setFragmentResultListener) + } binding.openQueue.setOnClickListener { PlayingQueueSheet().show(childFragmentManager) } diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt index f8d0e1881..671700c60 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt @@ -5,9 +5,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.os.bundleOf +import androidx.fragment.app.setFragmentResult import androidx.media3.common.Player import androidx.recyclerview.widget.LinearLayoutManager import com.github.libretube.R +import com.github.libretube.constants.IntentData import com.github.libretube.databinding.QueueBottomSheetBinding import com.github.libretube.db.DatabaseHelper import com.github.libretube.db.DatabaseHolder @@ -41,7 +44,9 @@ class PlayingQueueSheet : ExpandedBottomSheet() { super.onViewCreated(view, savedInstanceState) binding.optionsRecycler.layoutManager = LinearLayoutManager(context) - val adapter = PlayingQueueAdapter() + val adapter = PlayingQueueAdapter { videoId -> + setFragmentResult(PLAYING_QUEUE_REQUEST_KEY, bundleOf(IntentData.videoId to videoId)) + } binding.optionsRecycler.adapter = adapter // scroll to the currently playing video in the queue @@ -201,4 +206,8 @@ class PlayingQueueSheet : ExpandedBottomSheet() { } .show() } + + companion object { + const val PLAYING_QUEUE_REQUEST_KEY = "playing_queue_request_key" + } } diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index fa34cbf3d..a0f8bf1c7 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -44,6 +44,7 @@ import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.PlayerGestureControlsViewBinding import com.github.libretube.extensions.dpToPx +import com.github.libretube.extensions.navigateVideo import com.github.libretube.extensions.normalize import com.github.libretube.extensions.round import com.github.libretube.extensions.seekBy @@ -257,6 +258,14 @@ abstract class CustomExoPlayerView( } } + supportFragmentManager.setFragmentResultListener( + PlayingQueueSheet.PLAYING_QUEUE_REQUEST_KEY, + findViewTreeLifecycleOwner()!! + ) { _, args -> + (player as? MediaController)?.navigateVideo( + args.getString(IntentData.videoId) ?: return@setFragmentResultListener + ) + } binding.queueToggle.setOnClickListener { PlayingQueueSheet().show(supportFragmentManager, null) } @@ -675,7 +684,8 @@ abstract class CustomExoPlayerView( // add a margin to the top and the bottom bar in landscape mode for notches val isForcedLandscape = activity.requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE - val isInLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + val isInLandscape = + resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE val horizontalMargin = if (isFullscreen() && (isInLandscape || isForcedLandscape)) LANDSCAPE_MARGIN_HORIZONTAL else LANDSCAPE_MARGIN_HORIZONTAL_NONE @@ -843,15 +853,16 @@ abstract class CustomExoPlayerView( } KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_NAVIGATE_NEXT -> { - PlayingQueue.navigateNext() + PlayingQueue.getNext()?.let { (player as? MediaController)?.navigateVideo(it) } } KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_NAVIGATE_PREVIOUS -> { - PlayingQueue.navigatePrev() + PlayingQueue.getPrev()?.let { (player as? MediaController)?.navigateVideo(it) } } KeyEvent.KEYCODE_F -> { - val fragmentManager = ContextHelper.unwrapActivity(context).supportFragmentManager + val fragmentManager = + ContextHelper.unwrapActivity(context).supportFragmentManager fragmentManager.fragments.filterIsInstance().firstOrNull() ?.toggleFullscreen() } diff --git a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt index 8fc7243bf..af5b458d9 100644 --- a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt +++ b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt @@ -1,6 +1,5 @@ package com.github.libretube.util -import android.util.Log import androidx.media3.common.Player import com.github.libretube.api.PlaylistsHelper import com.github.libretube.api.RetrofitInstance @@ -20,11 +19,6 @@ object PlayingQueue { private val queueJobs = mutableListOf() - /** - * Listener that gets called when the user selects an item from the queue - */ - private var onQueueTapListener: (StreamItem) -> Unit = {} - var repeatMode: Int = Player.REPEAT_MODE_OFF fun clear() { @@ -223,34 +217,7 @@ object PlayingQueue { add(*streams.filter { !it.isLive }.toTypedArray(), skipExisting = true) } - fun onQueueItemSelected(index: Int) { - try { - val streamItem = queue[index] - updateCurrent(streamItem) - onQueueTapListener.invoke(streamItem) - } catch (e: Exception) { - Log.e("Queue on tap", "lifecycle already ended") - } - } - - fun navigatePrev() { - if (!hasPrev()) return - - onQueueItemSelected(currentIndex() - 1) - } - - fun navigateNext() { - if (!hasNext()) return - - onQueueItemSelected(currentIndex() + 1) - } - - fun setOnQueueTapListener(listener: (StreamItem) -> Unit) { - onQueueTapListener = listener - } - fun resetToDefaults() { repeatMode = Player.REPEAT_MODE_OFF - onQueueTapListener = {} } }