Add Auto-play option (#600)

* Rewrite and clean up player controls and activity

* rename crashlogs to aniyomi

* Update PlayerActivity.kt

* Add auto play option + clean up portrait layout

* add "updateLayoutParams" import
This commit is contained in:
Quickdesh 2022-05-26 02:26:20 +09:00 committed by GitHub
parent 5b40fa3d71
commit 4fee596b0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 13 deletions

View file

@ -13,6 +13,8 @@ object PreferenceKeys {
const val pipEpisodeToasts = "pref_pip_episode_toasts"
const val autoplayEnabled = "pref_auto_play_enabled"
const val mpvConf = "pref_mpv_conf"
const val defaultOrientationType = "pref_default_orientation_type_key"

View file

@ -121,6 +121,8 @@ class PreferencesHelper(val context: Context) {
fun pipEpisodeToasts() = prefs.getBoolean(Keys.pipEpisodeToasts, true)
fun autoplayEnabled() = flowPrefs.getBoolean(Keys.autoplayEnabled, false)
fun mpvConf() = prefs.getString(Keys.mpvConf, "")
fun defaultOrientationType() = prefs.getInt(Keys.defaultOrientationType, OrientationType.FREE.flagValue)

View file

@ -36,11 +36,13 @@ import android.view.animation.AnimationUtils
import android.widget.LinearLayout
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.animesource.model.Track
@ -291,7 +293,9 @@ class PlayerActivity :
}
setVisibilities()
playerControls.showAndFadeControls()
toggleAutoplay(preferences.autoplayEnabled().get())
setMpvConf()
player.initialize(applicationContext.filesDir.path)
@ -372,10 +376,44 @@ class PlayerActivity :
if (width <= height) {
width = height.also { height = width }
}
playerControls.binding.titleMainTxt.updateLayoutParams<ConstraintLayout.LayoutParams> {
rightToLeft = playerControls.binding.toggleAutoplay.id
rightToRight = ConstraintLayout.LayoutParams.UNSET
}
playerControls.binding.titleSecondaryTxt.updateLayoutParams<ConstraintLayout.LayoutParams> {
rightToLeft = playerControls.binding.toggleAutoplay.id
rightToRight = ConstraintLayout.LayoutParams.UNSET
}
playerControls.binding.qualityBtn.updateLayoutParams<ConstraintLayout.LayoutParams> {
topToTop = ConstraintLayout.LayoutParams.PARENT_ID
topToBottom = ConstraintLayout.LayoutParams.UNSET
}
playerControls.binding.toggleAutoplay.updateLayoutParams<ConstraintLayout.LayoutParams> {
leftToLeft = ConstraintLayout.LayoutParams.UNSET
leftToRight = playerControls.binding.titleMainTxt.id
}
} else {
if (width >= height) {
width = height.also { height = width }
}
playerControls.binding.titleMainTxt.updateLayoutParams<ConstraintLayout.LayoutParams> {
rightToLeft = ConstraintLayout.LayoutParams.UNSET
rightToRight = ConstraintLayout.LayoutParams.PARENT_ID
}
playerControls.binding.titleSecondaryTxt.updateLayoutParams<ConstraintLayout.LayoutParams> {
rightToLeft = ConstraintLayout.LayoutParams.UNSET
rightToRight = ConstraintLayout.LayoutParams.PARENT_ID
}
playerControls.binding.qualityBtn.updateLayoutParams<ConstraintLayout.LayoutParams> {
topToTop = ConstraintLayout.LayoutParams.UNSET
topToBottom = playerControls.binding.backArrowBtn.id
}
playerControls.binding.toggleAutoplay.updateLayoutParams<ConstraintLayout.LayoutParams> {
leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID
leftToRight = ConstraintLayout.LayoutParams.UNSET
}
}
setupGestures()
setViewMode()
@ -424,7 +462,7 @@ class PlayerActivity :
showLoadingIndicator(true)
val epTxt = switchMethod {
if (wasPlayerPaused == false) {
if (wasPlayerPaused == false || preferences.autoplayEnabled().get()) {
player.paused = false
}
}
@ -436,10 +474,37 @@ class PlayerActivity :
}
}
// Fade out Player information text
private val playerInformationRunnable = Runnable {
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
playerControls.binding.playerInformation.startAnimation(fadeAnimation)
playerControls.binding.playerInformation.visibility = View.GONE
}
}
internal fun toggleAutoplay(isAutoplay: Boolean) {
playerControls.binding.toggleAutoplay.isChecked = isAutoplay
playerControls.binding.toggleAutoplay.thumbDrawable = if (isAutoplay) {
ContextCompat.getDrawable(playerControls.context, R.drawable.ic_play_circle_filled_24)
} else ContextCompat.getDrawable(playerControls.context, R.drawable.ic_pause_circle_filled_24)
if (isAutoplay) {
playerControls.binding.playerInformation.text = getString(R.string.enable_auto_play)
} else {
playerControls.binding.playerInformation.text = getString(R.string.disable_auto_play)
}
if (!preferences.autoplayEnabled().get() == isAutoplay) {
animationHandler.removeCallbacks(playerInformationRunnable)
playerControls.binding.playerInformation.visibility = View.VISIBLE
animationHandler.postDelayed(playerInformationRunnable, 1000L)
}
preferences.autoplayEnabled().set(isAutoplay)
}
fun toggleControls() = playerControls.toggleControls()
private fun showLoadingIndicator(visible: Boolean) {
if (binding.loadingIndicator.isVisible == visible) return
playerControls.binding.playBtn.isVisible = !visible
binding.loadingIndicator.isVisible = visible
}
@ -771,8 +836,8 @@ class PlayerActivity :
// forces update of entire UI, used when resuming the activity
val paused = player.paused ?: return
updatePlaybackStatus(paused)
player.timePos?.let { playerControls.updatePlaybackPos(it) }
player.duration?.let { playerControls.updatePlaybackDuration(it) }
player.timePos?.let { playerControls.updatePlaybackPos(it) }
updatePlaylistButtons()
updateEpisodeText()
player.loadTracks()
@ -1147,6 +1212,14 @@ class PlayerActivity :
"pause" -> {
if (!isFinishing) {
setAudioFocus(value)
if (player.timePos != null && player.duration != null) {
val isVideoEof = MPVLib.getPropertyBoolean("eof-reached") == true
val isVideoCompleted = isVideoEof || (player.timePos!! >= player.duration!!)
if (isVideoCompleted && preferences.autoplayEnabled().get()) {
animationHandler.postDelayed({ switchEpisode(false) }, 1000L)
}
}
updatePlaybackStatus(value)
}
}
@ -1181,4 +1254,4 @@ private const val CONTROL_TYPE_PAUSE = 2
private const val REQUEST_PREVIOUS = 3
private const val REQUEST_NEXT = 4
private const val CONTROL_TYPE_PREVIOUS = 3
private const val CONTROL_TYPE_NEXT = 4
private const val CONTROL_TYPE_NEXT = 4

View file

@ -80,6 +80,10 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
binding.nextBtn.setOnClickListener { activity.switchEpisode(false) }
binding.prevBtn.setOnClickListener { activity.switchEpisode(true) }
binding.toggleAutoplay.setOnCheckedChangeListener { _, isChecked ->
activity.toggleAutoplay(isChecked)
}
}
private val animationHandler = Handler(Looper.getMainLooper())
@ -290,4 +294,4 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
}
picker.number = MPVLib.getPropertyDouble("speed")
}
}
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportHeight="24"
android:viewportWidth="24"
android:height="24dp"
android:width="24dp">
<path
android:fillColor="?attr/colorOnPrimarySurface"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,16L9,16L9,8h2v8zM15,16h-2L13,8h2v8z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportHeight="24"
android:viewportWidth="24"
android:height="24dp"
android:width="24dp">
<path
android:fillColor="?attr/colorControlActivated"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5 -6,4.5z"/>
</vector>

View file

@ -62,7 +62,7 @@
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@id/backArrowBtn"
app:layout_constraintRight_toLeftOf="@id/cycleDecoderBtn"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@ -75,7 +75,7 @@
android:textColor="?attr/colorOnPrimarySurface"
android:textSize="12sp"
app:layout_constraintLeft_toRightOf="@id/backArrowBtn"
app:layout_constraintRight_toLeftOf="@id/cycleDecoderBtn"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleMainTxt" />
<!-- Top Controls (Left)-->
@ -90,11 +90,11 @@
android:contentDescription="Settings"
android:onClick="openQuality"
android:src="@drawable/ic_video_quality_24dp"
app:layout_constraintLeft_toRightOf="@id/cycleSubsBtn"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@id/backArrowBtn"
app:tint="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/cycleSubsBtn"
android:layout_width="48dp"
@ -103,6 +103,7 @@
android:contentDescription="Subtitles"
android:onClick="cycleSub"
android:src="@drawable/ic_subtitles_black_24dp"
app:layout_constraintLeft_toRightOf="@id/cycleAudioBtn"
app:layout_constraintRight_toLeftOf="@id/qualityBtn"
app:layout_constraintTop_toTopOf="@id/qualityBtn"
app:tint="?attr/colorOnPrimarySurface" />
@ -115,6 +116,7 @@
android:contentDescription="Audio"
android:onClick="cycleAudio"
android:src="@drawable/ic_audiotrack_black_24dp"
app:layout_constraintLeft_toRightOf="@id/cycleDecoderBtn"
app:layout_constraintRight_toLeftOf="@id/cycleSubsBtn"
app:layout_constraintTop_toTopOf="@id/cycleSubsBtn"
app:tint="?attr/colorOnPrimarySurface" />
@ -127,9 +129,18 @@
android:onClick="switchDecoder"
android:text=".."
android:textColor="?attr/colorOnPrimarySurface"
app:layout_constraintLeft_toRightOf="@id/toggleAutoplay"
app:layout_constraintRight_toLeftOf="@id/cycleAudioBtn"
app:layout_constraintTop_toTopOf="@id/cycleAudioBtn" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/toggleAutoplay"
android:layout_width="64dp"
android:layout_height="48dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/cycleDecoderBtn"
app:layout_constraintTop_toTopOf="@id/cycleDecoderBtn" />
<!-- Audio -->
<TextView
@ -240,7 +251,7 @@
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:text="0:00:00"
android:text="0:00"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
@ -264,7 +275,7 @@
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:text="0:00:00"
android:text="0:00"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
@ -290,7 +301,6 @@
android:id="@+id/play_btn"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Play/Pause"
android:onClick="playPause"
@ -304,6 +314,21 @@
tools:src="@drawable/ic_play_arrow_80dp"
tools:visibility="visible" />
<TextView
android:id="@+id/playerInformation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="left"
android:text="Information"
android:textColor="#FFFFFF"
android:textSize="14sp"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/play_btn"
tools:visibility="visible" />
<ImageButton
android:id="@+id/nextBtn"
android:layout_width="72dp"
@ -406,4 +431,4 @@
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View file

@ -995,6 +995,8 @@
<string name="label_updates">Manga</string>
<string name="label_animeupdates">Anime</string>
<string name="player_overlay_back">Back</string>
<string name="enable_auto_play">"Auto-play is on"</string>
<string name="disable_auto_play">"Auto-play is off"</string>
<!-- Aniyomi stuff -->
<string name="playback_speed_dialog_title">Change playback speed:</string>