Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoplay Countdown when the video ended (optional) #3159

Merged
merged 3 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,8 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
// save the watch position to the database
// only called when the position is unequal to 0, otherwise it would become reset
// before the player can seek to the saved position from videos of the queue
if (exoPlayer.currentPosition != 0L) saveWatchPosition()
// not called when the video has ended, since it then might save it to the next autoplay video
if (exoPlayer.currentPosition != 0L && playbackState != Player.STATE_ENDED) saveWatchPosition()

// check if video has ended, next video is available and autoplay is enabled.
if (
Expand All @@ -922,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) {
Expand Down Expand Up @@ -1014,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
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
}
41 changes: 41 additions & 0 deletions app/src/main/res/layout/autoplay_countdown.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#aa000000">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">

<TextView
android:id="@+id/current_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">

<com.google.android.material.button.MaterialButton
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel" />

<com.google.android.material.button.MaterialButton
android:id="@+id/playNext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@string/play_next" />

</LinearLayout>

</LinearLayout>

</FrameLayout>
6 changes: 6 additions & 0 deletions app/src/main/res/layout/fragment_player.xml
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,12 @@
app:drawableTint="@android:color/white" />

</com.google.android.material.card.MaterialCardView>

<com.github.libretube.ui.views.AutoplayCountdownView
android:id="@+id/autoplay_countdown"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />

</com.github.libretube.ui.views.CustomExoPlayerView>

Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@
<string name="category">Category</string>
<string name="stats_for_nerds">Stats for nerds</string>
<string name="video_id">Video ID</string>
<string name="autoplay_countdown">Autoplay countdown</string>
<string name="autoplay_countdown_summary">Show a 5s countdown before auto-playing the next video.</string>
<string name="playing_next">Playing next in %1$s</string>
<!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string>
<string name="download_channel_description">Shows a notification when downloading media.</string>
Expand Down
17 changes: 12 additions & 5 deletions app/src/main/res/xml/player_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_headphones"
android:summary="@string/alternative_pip_controls_summary"
app:key="alternative_pip_controls"
app:title="@string/alternative_pip_controls"
android:summary="@string/alternative_pip_controls_summary"/>
app:title="@string/alternative_pip_controls" />

<SwitchPreferenceCompat
android:defaultValue="false"
Expand Down Expand Up @@ -159,16 +159,23 @@
app:key="autoplay"
app:title="@string/player_autoplay" />

<SwitchPreferenceCompat
android:icon="@drawable/ic_speed"
android:summary="@string/autoplay_countdown_summary"
app:defaultValue="false"
app:key="autoplay_countdown"
app:title="@string/autoplay_countdown" />

</PreferenceCategory>

<PreferenceCategory app:title="@string/background_mode">

<SwitchPreferenceCompat
android:icon="@drawable/ic_headphones"
android:summary="@string/custom_playback_speed_summary"
app:defaultValue="false"
app:key="custom_playback_speed"
app:title="@string/custom_playback_speed"
android:summary="@string/custom_playback_speed_summary"
android:icon="@drawable/ic_headphones" />
app:title="@string/custom_playback_speed" />

<com.github.libretube.ui.views.SliderPreference
android:icon="@drawable/ic_speed"
Expand Down