diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt
index 71b3576e1..2c76f69dc 100644
--- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt
+++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt
@@ -92,6 +92,7 @@ object PreferenceKeys {
const val ALTERNATIVE_PIP_CONTROLS = "alternative_pip_controls"
const val SKIP_SILENCE = "skip_silence"
const val ENABLED_VIDEO_CODECS = "video_codecs"
+ const val AUTOPLAY_COUNTDOWN = "autoplay_countdown"
/**
* Background mode
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 ab032a2a8..d75979cdd 100644
--- a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt
+++ b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt
@@ -274,6 +274,12 @@ object PlayerHelper {
true
)
+ val autoPlayCountdown: Boolean
+ get() = PreferenceHelper.getBoolean(
+ PreferenceKeys.AUTOPLAY_COUNTDOWN,
+ false
+ )
+
val seekIncrement: Long
get() = PreferenceHelper.getString(
PreferenceKeys.SEEK_INCREMENT,
diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
index b6040f926..dd3b4252c 100644
--- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
+++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
@@ -923,7 +923,11 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
binding.player.autoplayEnabled
) {
transitioning = true
- playNextVideo()
+ if (PlayerHelper.autoPlayCountdown) {
+ showAutoPlayCountdown()
+ } else {
+ playNextVideo()
+ }
}
if (playbackState == Player.STATE_READY) {
@@ -1015,6 +1019,18 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
}
}
+ private fun showAutoPlayCountdown() {
+ binding.player.useController = false
+ binding.player.hideController()
+ binding.autoplayCountdown.setHideSelfListener {
+ binding.autoplayCountdown.visibility = View.GONE
+ binding.player.useController = true
+ }
+ binding.autoplayCountdown.startCountdown {
+ playNextVideo()
+ }
+ }
+
/**
* Set up the description text with video links and timestamps
*/
diff --git a/app/src/main/java/com/github/libretube/ui/views/AutoplayCountdownView.kt b/app/src/main/java/com/github/libretube/ui/views/AutoplayCountdownView.kt
new file mode 100644
index 000000000..2f58ca2e4
--- /dev/null
+++ b/app/src/main/java/com/github/libretube/ui/views/AutoplayCountdownView.kt
@@ -0,0 +1,68 @@
+package com.github.libretube.ui.views
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.os.postDelayed
+import com.github.libretube.R
+import com.github.libretube.databinding.AutoplayCountdownBinding
+
+class AutoplayCountdownView(
+ context: Context,
+ attributeSet: AttributeSet?
+) : FrameLayout(context, attributeSet) {
+ private val layoutInflater = LayoutInflater.from(context)
+ val binding = AutoplayCountdownBinding.inflate(layoutInflater, this, true)
+ private var onCountdownEnd: () -> Unit = {}
+ private var hideSelf: () -> Unit = {}
+ private val handler = Handler(Looper.getMainLooper())
+ private var currentTimerState = COUNTDOWN_SECONDS
+
+ init {
+ binding.cancel.setOnClickListener {
+ handler.removeCallbacksAndMessages(TIMER_RUNNABLE_TOKEN)
+ hideSelf.invoke()
+ }
+ }
+
+ fun setHideSelfListener(listener: () -> Unit) {
+ hideSelf = listener
+ }
+
+ fun startCountdown(onEnd: () -> Unit) {
+ this.visibility = View.VISIBLE
+ onCountdownEnd = {
+ hideSelf.invoke()
+ onEnd.invoke()
+ }
+ currentTimerState = COUNTDOWN_SECONDS
+ binding.playNext.setOnClickListener {
+ handler.removeCallbacksAndMessages(TIMER_RUNNABLE_TOKEN)
+ onCountdownEnd.invoke()
+ }
+ updateCountdown()
+ }
+
+ private fun updateCountdown() {
+ if (currentTimerState == 0) {
+ onCountdownEnd.invoke()
+ return
+ }
+
+ binding.currentState.text = context.getString(
+ R.string.playing_next,
+ currentTimerState.toString()
+ )
+ currentTimerState -= 1
+ handler.postDelayed(1000, TIMER_RUNNABLE_TOKEN, this::updateCountdown)
+ }
+
+ companion object {
+ private const val COUNTDOWN_SECONDS = 5
+ private const val TIMER_RUNNABLE_TOKEN = "timer_runnable"
+ }
+}
diff --git a/app/src/main/res/layout/autoplay_countdown.xml b/app/src/main/res/layout/autoplay_countdown.xml
new file mode 100644
index 000000000..80d1b7322
--- /dev/null
+++ b/app/src/main/res/layout/autoplay_countdown.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml
index 29be2c33c..70c586f9a 100644
--- a/app/src/main/res/layout/fragment_player.xml
+++ b/app/src/main/res/layout/fragment_player.xml
@@ -349,6 +349,12 @@
app:drawableTint="@android:color/white" />
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ac54ad6d6..7cb818bc6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -446,6 +446,9 @@
Category
Stats for nerds
Video ID
+ Autoplay countdown
+ Show a 5s countdown before auto-playing the next video.
+ Playing next in %1$s
Download Service
Shows a notification when downloading media.
diff --git a/app/src/main/res/xml/player_settings.xml b/app/src/main/res/xml/player_settings.xml
index 7f438e031..b64503c28 100644
--- a/app/src/main/res/xml/player_settings.xml
+++ b/app/src/main/res/xml/player_settings.xml
@@ -41,9 +41,9 @@
+ app:title="@string/alternative_pip_controls" />
+
+
+ app:title="@string/custom_playback_speed" />