From 4fee596b0a625f574172cd1286d08303b13bafb1 Mon Sep 17 00:00:00 2001 From: Quickdesh <36792807+Quickdesh@users.noreply.github.com> Date: Thu, 26 May 2022 02:26:20 +0900 Subject: [PATCH] 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 --- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 2 + .../tachiyomi/ui/player/PlayerActivity.kt | 81 ++++++++++++++++++- .../tachiyomi/ui/player/PlayerControlsView.kt | 6 +- .../drawable/ic_pause_circle_filled_24.xml | 9 +++ .../res/drawable/ic_play_circle_filled_24.xml | 9 +++ app/src/main/res/layout/player_controls.xml | 41 ++++++++-- app/src/main/res/values/strings.xml | 2 + 8 files changed, 139 insertions(+), 13 deletions(-) create mode 100644 app/src/main/res/drawable/ic_pause_circle_filled_24.xml create mode 100644 app/src/main/res/drawable/ic_play_circle_filled_24.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 2e3020feb..59af3523e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -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" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 93b524027..f88827291 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt index 8042ffd21..e111b8362 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt @@ -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 { + rightToLeft = playerControls.binding.toggleAutoplay.id + rightToRight = ConstraintLayout.LayoutParams.UNSET + } + playerControls.binding.titleSecondaryTxt.updateLayoutParams { + rightToLeft = playerControls.binding.toggleAutoplay.id + rightToRight = ConstraintLayout.LayoutParams.UNSET + } + playerControls.binding.qualityBtn.updateLayoutParams { + topToTop = ConstraintLayout.LayoutParams.PARENT_ID + topToBottom = ConstraintLayout.LayoutParams.UNSET + } + playerControls.binding.toggleAutoplay.updateLayoutParams { + leftToLeft = ConstraintLayout.LayoutParams.UNSET + leftToRight = playerControls.binding.titleMainTxt.id + } } else { if (width >= height) { width = height.also { height = width } } + + playerControls.binding.titleMainTxt.updateLayoutParams { + rightToLeft = ConstraintLayout.LayoutParams.UNSET + rightToRight = ConstraintLayout.LayoutParams.PARENT_ID + } + playerControls.binding.titleSecondaryTxt.updateLayoutParams { + rightToLeft = ConstraintLayout.LayoutParams.UNSET + rightToRight = ConstraintLayout.LayoutParams.PARENT_ID + } + playerControls.binding.qualityBtn.updateLayoutParams { + topToTop = ConstraintLayout.LayoutParams.UNSET + topToBottom = playerControls.binding.backArrowBtn.id + } + playerControls.binding.toggleAutoplay.updateLayoutParams { + 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 \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerControlsView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerControlsView.kt index b3f757cb9..b9e6f381c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerControlsView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerControlsView.kt @@ -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") } -} +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_pause_circle_filled_24.xml b/app/src/main/res/drawable/ic_pause_circle_filled_24.xml new file mode 100644 index 000000000..db21593eb --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_circle_filled_24.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play_circle_filled_24.xml b/app/src/main/res/drawable/ic_play_circle_filled_24.xml new file mode 100644 index 000000000..f384b3254 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_circle_filled_24.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/player_controls.xml b/app/src/main/res/layout/player_controls.xml index 28054c418..6bd862703 100644 --- a/app/src/main/res/layout/player_controls.xml +++ b/app/src/main/res/layout/player_controls.xml @@ -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" /> @@ -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" /> - @@ -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" /> + + @@ -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" /> + + - + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index afecccb16..3ca5d91a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -995,6 +995,8 @@ Manga Anime Back + "Auto-play is on" + "Auto-play is off" Change playback speed: