diff --git a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt index f78b3ffd3..21a8ac25d 100644 --- a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt @@ -18,6 +18,7 @@ import androidx.core.net.toUri import androidx.media3.common.AudioAttributes import androidx.media3.common.C import androidx.media3.common.PlaybackParameters +import androidx.media3.common.Player import androidx.media3.common.Tracks import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.cronet.CronetDataSource @@ -53,6 +54,12 @@ object PlayerHelper { const val ROLE_FLAG_AUTO_GEN_SUBTITLE = C.ROLE_FLAG_SUPPLEMENTARY const val MINIMUM_BUFFER_DURATION = 1000 * 10 // exo default is 50s + val repeatModes = listOf( + Player.REPEAT_MODE_OFF to R.string.repeat_mode_none, + Player.REPEAT_MODE_ONE to R.string.repeat_mode_current, + Player.REPEAT_MODE_ALL to R.string.repeat_mode_all + ) + /** * A list of all categories that are not disabled by default * Also update `sponsorblock_settings.xml` when modifying this! 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 4f1b036d4..a10cae728 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,6 +5,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.media3.common.Player import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -77,10 +78,15 @@ class PlayingQueueSheet : ExpandedBottomSheet() { } binding.repeat.setOnClickListener { - PlayingQueue.repeatQueue = !PlayingQueue.repeatQueue - it.alpha = if (PlayingQueue.repeatQueue) 1f else 0.5f + // select the next available repeat mode + PlayingQueue.repeatMode = when (PlayingQueue.repeatMode) { + Player.REPEAT_MODE_OFF -> Player.REPEAT_MODE_ONE + Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ALL + else -> Player.REPEAT_MODE_OFF + } + updateRepeatButton() } - binding.repeat.alpha = if (PlayingQueue.repeatQueue) 1f else 0.5f + updateRepeatButton() binding.clearQueue.setOnClickListener { val currentIndex = PlayingQueue.currentIndex() @@ -135,6 +141,12 @@ class PlayingQueueSheet : ExpandedBottomSheet() { itemTouchHelper.attachToRecyclerView(binding.optionsRecycler) } + private fun updateRepeatButton() { + binding.repeat.alpha = if (PlayingQueue.repeatMode == Player.REPEAT_MODE_OFF) 0.5f else 1f + val drawableResource = if (PlayingQueue.repeatMode == Player.REPEAT_MODE_ONE) R.drawable.ic_repeat_one else R.drawable.ic_repeat + binding.repeat.setImageResource(drawableResource) + } + @SuppressLint("NotifyDataSetChanged") private fun showSortDialog() { val sortOptions = listOf( 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 f98bf9c4f..f293228a3 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 @@ -25,7 +25,6 @@ import androidx.core.view.updateLayoutParams import androidx.media3.common.C import androidx.media3.common.Player import androidx.media3.common.text.Cue -import androidx.media3.common.util.RepeatModeUtil import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.CaptionStyleCompat @@ -296,10 +295,11 @@ open class CustomExoPlayerView( context.getString(R.string.repeat_mode), R.drawable.ic_repeat, { - if (player?.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) { - context.getString(R.string.repeat_mode_none) - } else { - context.getString(R.string.repeat_mode_current) + when (PlayingQueue.repeatMode) { + Player.REPEAT_MODE_OFF -> context.getString(R.string.repeat_mode_none) + Player.REPEAT_MODE_ONE -> context.getString(R.string.repeat_mode_current) + Player.REPEAT_MODE_ALL -> context.getString(R.string.repeat_mode_all) + else -> throw IllegalArgumentException() } } ) { @@ -527,27 +527,10 @@ open class CustomExoPlayerView( } override fun onRepeatModeClicked() { - val repeatModeNames = listOf( - context.getString(R.string.repeat_mode_none), - context.getString(R.string.repeat_mode_current), - context.getString(R.string.all) - ) // repeat mode options dialog BaseBottomSheet() - .setSimpleItems(repeatModeNames) { index -> - PlayingQueue.repeatQueue = when (index) { - 0 -> { - player?.repeatMode = Player.REPEAT_MODE_OFF - false - } - - 1 -> { - player?.repeatMode = Player.REPEAT_MODE_ONE - false - } - - else -> true - } + .setSimpleItems(PlayerHelper.repeatModes.map { context.getString(it.second) }) { index -> + PlayingQueue.repeatMode = PlayerHelper.repeatModes[index].first } .show(supportFragmentManager) } 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 61ba7db80..f2b5897db 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,7 @@ 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 import com.github.libretube.api.obj.StreamItem @@ -20,7 +21,7 @@ object PlayingQueue { */ private var onQueueTapListener: (StreamItem) -> Unit = {} - var repeatQueue: Boolean = false + var repeatMode: Int = Player.REPEAT_MODE_OFF fun clear() = queue.clear() @@ -51,12 +52,30 @@ object PlayingQueue { } // return the next item, or if repeating enabled, the first one of the queue - fun getNext(): String? = queue.getOrNull(currentIndex() + 1)?.url?.toID() - ?: queue.firstOrNull()?.url?.toID()?.takeIf { repeatQueue } + fun getNext(): String? { + if (repeatMode != Player.REPEAT_MODE_ONE) { + queue.getOrNull(currentIndex() + 1)?.url?.toID()?.let { return it } + } + + return when (repeatMode) { + Player.REPEAT_MODE_ALL -> queue.firstOrNull()?.url?.toID() + Player.REPEAT_MODE_ONE -> currentStream?.url?.toID() + else -> null + } + } // return the previous item, or if repeating enabled, the last one of the queue - fun getPrev(): String? = queue.getOrNull(currentIndex() - 1)?.url?.toID() - ?: queue.lastOrNull()?.url?.toID()?.takeIf { repeatQueue } + fun getPrev(): String? { + if (repeatMode != Player.REPEAT_MODE_ONE) { + queue.getOrNull(currentIndex() - 1)?.url?.toID()?.let { return it } + } + + return when (repeatMode) { + Player.REPEAT_MODE_ALL -> queue.lastOrNull()?.url?.toID() + Player.REPEAT_MODE_ONE -> currentStream?.url?.toID() + else -> null + } + } fun hasPrev() = getPrev() != null @@ -214,7 +233,7 @@ object PlayingQueue { } fun resetToDefaults() { - repeatQueue = false + repeatMode = Player.REPEAT_MODE_OFF onQueueTapListener = {} } diff --git a/app/src/main/res/drawable/ic_repeat_one.xml b/app/src/main/res/drawable/ic_repeat_one.xml new file mode 100644 index 000000000..e8c7449eb --- /dev/null +++ b/app/src/main/res/drawable/ic_repeat_one.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e8a90bc2..4426cb2d3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -270,6 +270,7 @@ Zoom None Current + Repeat all Backup & restore Backup Picture-in-Picture