mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-29 09:39:03 +03:00
attempt to declutter the player activity and layout
This commit is contained in:
parent
0890a21eb2
commit
6c7e012e40
4 changed files with 668 additions and 603 deletions
|
@ -29,12 +29,8 @@ import android.view.View
|
||||||
import android.view.ViewAnimationUtils
|
import android.view.ViewAnimationUtils
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.SeekBar
|
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.GestureDetectorCompat
|
import androidx.core.view.GestureDetectorCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
@ -54,9 +50,6 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import `is`.xyz.mpv.MPVLib
|
import `is`.xyz.mpv.MPVLib
|
||||||
import `is`.xyz.mpv.PickerDialog
|
|
||||||
import `is`.xyz.mpv.SpeedPickerDialog
|
|
||||||
import `is`.xyz.mpv.StateRestoreCallback
|
|
||||||
import `is`.xyz.mpv.Utils
|
import `is`.xyz.mpv.Utils
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import nucleus.factory.RequiresPresenter
|
import nucleus.factory.RequiresPresenter
|
||||||
|
@ -85,17 +78,6 @@ class PlayerActivity :
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ACTION_MEDIA_CONTROL = "media_control"
|
|
||||||
private val EXTRA_CONTROL_TYPE = "control_type"
|
|
||||||
private val REQUEST_PLAY = 1
|
|
||||||
private val REQUEST_PAUSE = 2
|
|
||||||
private val CONTROL_TYPE_PLAY = 1
|
|
||||||
private val CONTROL_TYPE_PAUSE = 2
|
|
||||||
private val REQUEST_PREVIOUS = 3
|
|
||||||
private val REQUEST_NEXT = 4
|
|
||||||
private val CONTROL_TYPE_PREVIOUS = 3
|
|
||||||
private val CONTROL_TYPE_NEXT = 4
|
|
||||||
|
|
||||||
private var isInPipMode: Boolean = false
|
private var isInPipMode: Boolean = false
|
||||||
|
|
||||||
private var mReceiver: BroadcastReceiver? = null
|
private var mReceiver: BroadcastReceiver? = null
|
||||||
|
@ -104,7 +86,7 @@ class PlayerActivity :
|
||||||
|
|
||||||
private val langName = LocaleHelper.getSimpleLocaleDisplay(preferences.lang().get())
|
private val langName = LocaleHelper.getSimpleLocaleDisplay(preferences.lang().get())
|
||||||
|
|
||||||
private val player get() = binding.player
|
internal val player get() = binding.player
|
||||||
|
|
||||||
private var audioManager: AudioManager? = null
|
private var audioManager: AudioManager? = null
|
||||||
private var fineVolume = 0F
|
private var fineVolume = 0F
|
||||||
|
@ -117,7 +99,7 @@ class PlayerActivity :
|
||||||
|
|
||||||
internal var isLocked = false
|
internal var isLocked = false
|
||||||
|
|
||||||
private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) }
|
internal val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) }
|
||||||
|
|
||||||
private var audioFocusRestore: () -> Unit = {}
|
private var audioFocusRestore: () -> Unit = {}
|
||||||
|
|
||||||
|
@ -192,8 +174,6 @@ class PlayerActivity :
|
||||||
|
|
||||||
private var initialSeek = -1
|
private var initialSeek = -1
|
||||||
|
|
||||||
private var userIsOperatingSeekbar = false
|
|
||||||
|
|
||||||
private lateinit var mDetector: GestureDetectorCompat
|
private lateinit var mDetector: GestureDetectorCompat
|
||||||
|
|
||||||
private val animationHandler = Handler(Looper.getMainLooper())
|
private val animationHandler = Handler(Looper.getMainLooper())
|
||||||
|
@ -201,7 +181,7 @@ class PlayerActivity :
|
||||||
// Fade out seek text
|
// Fade out seek text
|
||||||
private val seekTextRunnable = Runnable {
|
private val seekTextRunnable = Runnable {
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
||||||
findViewById<LinearLayout>(R.id.seekView).startAnimation(fadeAnimation)
|
binding.seekView.startAnimation(fadeAnimation)
|
||||||
binding.seekView.visibility = View.GONE
|
binding.seekView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +189,7 @@ class PlayerActivity :
|
||||||
// Fade out Volume Bar
|
// Fade out Volume Bar
|
||||||
private val volumeViewRunnable = Runnable {
|
private val volumeViewRunnable = Runnable {
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
||||||
findViewById<LinearLayout>(R.id.volumeView).startAnimation(fadeAnimation)
|
binding.volumeView.startAnimation(fadeAnimation)
|
||||||
binding.volumeView.visibility = View.GONE
|
binding.volumeView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,24 +197,11 @@ class PlayerActivity :
|
||||||
// Fade out Brightness Bar
|
// Fade out Brightness Bar
|
||||||
private val brightnessViewRunnable = Runnable {
|
private val brightnessViewRunnable = Runnable {
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
||||||
findViewById<LinearLayout>(R.id.brightnessView).startAnimation(fadeAnimation)
|
binding.brightnessView.startAnimation(fadeAnimation)
|
||||||
binding.brightnessView.visibility = View.GONE
|
binding.brightnessView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fade out Player controls
|
|
||||||
private val controlsViewRunnable = Runnable {
|
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
|
||||||
if (!isLocked) {
|
|
||||||
findViewById<LinearLayout>(R.id.controlsView).startAnimation(fadeAnimation)
|
|
||||||
binding.controlsView.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
findViewById<LinearLayout>(R.id.lockedView).startAnimation(fadeAnimation)
|
|
||||||
binding.lockedView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showGestureView(type: String) {
|
private fun showGestureView(type: String) {
|
||||||
val callback: Runnable
|
val callback: Runnable
|
||||||
val itemView: LinearLayout
|
val itemView: LinearLayout
|
||||||
|
@ -255,11 +222,6 @@ class PlayerActivity :
|
||||||
itemView = binding.brightnessView
|
itemView = binding.brightnessView
|
||||||
delay = 500L
|
delay = 500L
|
||||||
}
|
}
|
||||||
"controls" -> {
|
|
||||||
callback = controlsViewRunnable
|
|
||||||
itemView = if (!isLocked) binding.controlsView else binding.lockedView
|
|
||||||
delay = 3500L
|
|
||||||
}
|
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,39 +230,21 @@ class PlayerActivity :
|
||||||
animationHandler.postDelayed(callback, delay)
|
animationHandler.postDelayed(callback, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val seekBarChangeListener = object : SeekBar.OnSeekBarChangeListener {
|
|
||||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
|
||||||
if (!fromUser) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
player.timePos = progress
|
|
||||||
updatePlaybackPos(progress)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
|
||||||
userIsOperatingSeekbar = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
|
||||||
userIsOperatingSeekbar = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentVideoList: List<Video>? = null
|
private var currentVideoList: List<Video>? = null
|
||||||
|
|
||||||
private var playerViewMode: Int = preferences.getPlayerViewMode()
|
private var playerViewMode: Int = preferences.getPlayerViewMode()
|
||||||
|
|
||||||
private var playerIsDestroyed = true
|
private var playerIsDestroyed = true
|
||||||
|
|
||||||
private var subTracks: Array<Track> = emptyArray()
|
internal var subTracks: Array<Track> = emptyArray()
|
||||||
|
|
||||||
private var selectedSub = 0
|
internal var selectedSub = 0
|
||||||
|
|
||||||
private var hadPreviousSubs = false
|
private var hadPreviousSubs = false
|
||||||
|
|
||||||
private var audioTracks: Array<Track> = emptyArray()
|
internal var audioTracks: Array<Track> = emptyArray()
|
||||||
|
|
||||||
private var selectedAudio = 0
|
internal var selectedAudio = 0
|
||||||
|
|
||||||
private var hadPreviousAudio = false
|
private var hadPreviousAudio = false
|
||||||
|
|
||||||
|
@ -320,7 +264,7 @@ class PlayerActivity :
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisibilities()
|
setVisibilities()
|
||||||
showGestureView("controls")
|
binding.playerControls.showAndFadeControls()
|
||||||
|
|
||||||
player.initialize(applicationContext.filesDir.path)
|
player.initialize(applicationContext.filesDir.path)
|
||||||
MPVLib.setOptionString("keep-open", "always")
|
MPVLib.setOptionString("keep-open", "always")
|
||||||
|
@ -351,29 +295,6 @@ class PlayerActivity :
|
||||||
mDetector.onTouchEvent(event)
|
mDetector.onTouchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
binding.pipBtn.isVisible = packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.backArrowBtn.setOnClickListener { finishAndRemoveTask() }
|
|
||||||
|
|
||||||
binding.pipBtn.setOnClickListener { startPiP() }
|
|
||||||
|
|
||||||
// Lock and Unlock controls
|
|
||||||
binding.lockBtn.setOnClickListener { isLocked = true; toggleControls() }
|
|
||||||
binding.unlockBtn.setOnClickListener { isLocked = false; toggleControls() }
|
|
||||||
|
|
||||||
// Cycle, Long click controls
|
|
||||||
binding.cycleAudioBtn.setOnLongClickListener { pickAudio(); true }
|
|
||||||
binding.cycleSpeedBtn.setOnLongClickListener { pickSpeed(); true }
|
|
||||||
binding.cycleSubsBtn.setOnLongClickListener { pickSub(); true }
|
|
||||||
|
|
||||||
binding.playbackSeekbar.setOnSeekBarChangeListener(seekBarChangeListener)
|
|
||||||
// player.playFile(currentVideoList!!.first().videoUrl!!.toString())
|
|
||||||
|
|
||||||
binding.nextBtn.setOnClickListener { switchEpisode(false) }
|
|
||||||
binding.prevBtn.setOnClickListener { switchEpisode(true) }
|
|
||||||
|
|
||||||
if (presenter?.needsInit() == true) {
|
if (presenter?.needsInit() == true) {
|
||||||
val anime = intent.extras!!.getLong("anime", -1)
|
val anime = intent.extras!!.getLong("anime", -1)
|
||||||
val episode = intent.extras!!.getLong("episode", -1)
|
val episode = intent.extras!!.getLong("episode", -1)
|
||||||
|
@ -391,7 +312,7 @@ class PlayerActivity :
|
||||||
* Switches to the previous episode if [previous] is true,
|
* Switches to the previous episode if [previous] is true,
|
||||||
* to the next episode if [previous] is false
|
* to the next episode if [previous] is false
|
||||||
*/
|
*/
|
||||||
private fun switchEpisode(previous: Boolean) {
|
internal fun switchEpisode(previous: Boolean) {
|
||||||
val switchMethod = if (previous) presenter::previousEpisode else presenter::nextEpisode
|
val switchMethod = if (previous) presenter::previousEpisode else presenter::nextEpisode
|
||||||
val errorRes = if (previous) R.string.no_previous_episode else R.string.no_next_episode
|
val errorRes = if (previous) R.string.no_previous_episode else R.string.no_next_episode
|
||||||
|
|
||||||
|
@ -414,92 +335,15 @@ class PlayerActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleControls() {
|
fun toggleControls() = binding.playerControls.toggleControls()
|
||||||
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
|
|
||||||
if (isLocked) {
|
|
||||||
// Hide controls
|
|
||||||
binding.controlsView.isVisible = false
|
|
||||||
|
|
||||||
if (!binding.lockedView.isVisible && !player.paused!!) showGestureView("controls")
|
|
||||||
else if (!binding.lockedView.isVisible && player.paused!!) binding.lockedView.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
else {
|
|
||||||
animationHandler.removeCallbacks(controlsViewRunnable)
|
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
|
||||||
findViewById<LinearLayout>(R.id.lockedView).startAnimation(fadeAnimation)
|
|
||||||
binding.lockedView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!binding.controlsView.isVisible && !player.paused!!) showGestureView("controls")
|
|
||||||
else if (!binding.controlsView.isVisible && player.paused!!) binding.controlsView.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
else {
|
|
||||||
animationHandler.removeCallbacks(controlsViewRunnable)
|
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
|
||||||
findViewById<LinearLayout>(R.id.controlsView).startAnimation(fadeAnimation)
|
|
||||||
binding.controlsView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.lockedView.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideControls(hide: Boolean) {
|
|
||||||
binding.controlsView.isVisible = !hide
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showLoadingIndicator(visible: Boolean) {
|
private fun showLoadingIndicator(visible: Boolean) {
|
||||||
if (binding.loadingIndicator.isVisible == visible) return
|
if (binding.loadingIndicator.isVisible == visible) return
|
||||||
binding.playBtn.isVisible = !visible
|
binding.playerControls.binding.playBtn.isVisible = !visible
|
||||||
binding.loadingIndicator.isVisible = visible
|
binding.loadingIndicator.isVisible = visible
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pickAudio() {
|
internal fun setSub(index: Int) {
|
||||||
val restore = pauseForDialog()
|
|
||||||
|
|
||||||
with(MaterialAlertDialogBuilder(this)) {
|
|
||||||
setSingleChoiceItems(
|
|
||||||
audioTracks.map { it.lang }.toTypedArray(),
|
|
||||||
selectedAudio,
|
|
||||||
) { dialog, item ->
|
|
||||||
if (item == selectedSub) return@setSingleChoiceItems
|
|
||||||
if (item == 0) {
|
|
||||||
selectedAudio = 0
|
|
||||||
player.aid = -1
|
|
||||||
return@setSingleChoiceItems
|
|
||||||
}
|
|
||||||
setAudio(item)
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
setOnDismissListener { restore() }
|
|
||||||
create().show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pickSub() {
|
|
||||||
val restore = pauseForDialog()
|
|
||||||
|
|
||||||
with(MaterialAlertDialogBuilder(this)) {
|
|
||||||
setSingleChoiceItems(
|
|
||||||
subTracks.map { it.lang }.toTypedArray(),
|
|
||||||
selectedSub,
|
|
||||||
) { dialog, item ->
|
|
||||||
if (item == 0) {
|
|
||||||
selectedSub = 0
|
|
||||||
player.sid = -1
|
|
||||||
return@setSingleChoiceItems
|
|
||||||
}
|
|
||||||
setSub(item)
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
setOnDismissListener { restore() }
|
|
||||||
create().show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setSub(index: Int) {
|
|
||||||
if (selectedSub == index || selectedSub > subTracks.lastIndex) return
|
if (selectedSub == index || selectedSub > subTracks.lastIndex) return
|
||||||
selectedSub = index
|
selectedSub = index
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
|
@ -515,7 +359,7 @@ class PlayerActivity :
|
||||||
?: MPVLib.command(arrayOf("sub-add", subTracks[index].url, "select", subTracks[index].url))
|
?: MPVLib.command(arrayOf("sub-add", subTracks[index].url, "select", subTracks[index].url))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setAudio(index: Int) {
|
internal fun setAudio(index: Int) {
|
||||||
if (selectedAudio == index || selectedAudio > audioTracks.lastIndex) return
|
if (selectedAudio == index || selectedAudio > audioTracks.lastIndex) return
|
||||||
selectedAudio = index
|
selectedAudio = index
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
|
@ -531,53 +375,6 @@ class PlayerActivity :
|
||||||
?: MPVLib.command(arrayOf("audio-add", audioTracks[index].url, "select", audioTracks[index].url))
|
?: MPVLib.command(arrayOf("audio-add", audioTracks[index].url, "select", audioTracks[index].url))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pauseForDialog(): StateRestoreCallback {
|
|
||||||
val wasPlayerPaused = player.paused ?: true // default to not changing state
|
|
||||||
player.paused = true
|
|
||||||
return {
|
|
||||||
if (!wasPlayerPaused) {
|
|
||||||
player.paused = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pickSpeed() {
|
|
||||||
// TODO: replace this with SliderPickerDialog
|
|
||||||
val picker = SpeedPickerDialog()
|
|
||||||
|
|
||||||
val restore = pauseForDialog()
|
|
||||||
speedPickerDialog(picker, R.string.title_speed_dialog) {
|
|
||||||
updateSpeedButton()
|
|
||||||
restore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun speedPickerDialog(
|
|
||||||
picker: PickerDialog,
|
|
||||||
@StringRes titleRes: Int,
|
|
||||||
restoreState: StateRestoreCallback,
|
|
||||||
) {
|
|
||||||
val dialog = with(AlertDialog.Builder(this)) {
|
|
||||||
setTitle(titleRes)
|
|
||||||
setView(picker.buildView(layoutInflater))
|
|
||||||
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
|
||||||
picker.number?.let {
|
|
||||||
if (picker.isInteger()) {
|
|
||||||
MPVLib.setPropertyInt("speed", it.toInt())
|
|
||||||
} else {
|
|
||||||
MPVLib.setPropertyDouble("speed", it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setNegativeButton(R.string.dialog_cancel) { dialog, _ -> dialog.cancel() }
|
|
||||||
setOnDismissListener { restoreState() }
|
|
||||||
create()
|
|
||||||
}
|
|
||||||
|
|
||||||
picker.number = MPVLib.getPropertyDouble("speed")
|
|
||||||
dialog.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setViewMode() {
|
private fun setViewMode() {
|
||||||
when (playerViewMode) {
|
when (playerViewMode) {
|
||||||
2 -> {
|
2 -> {
|
||||||
|
@ -610,67 +407,35 @@ class PlayerActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePlaybackPos(position: Int) {
|
|
||||||
binding.playbackPositionTxt.text = Utils.prettyTime(position)
|
|
||||||
if (!userIsOperatingSeekbar) {
|
|
||||||
binding.playbackSeekbar.progress = position
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDecoderButton()
|
|
||||||
updateSpeedButton()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updatePlaybackDuration(duration: Int) {
|
|
||||||
binding.playbackDurationTxt.text = Utils.prettyTime(duration)
|
|
||||||
if (!userIsOperatingSeekbar) {
|
|
||||||
binding.playbackSeekbar.max = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateDecoderButton() {
|
|
||||||
if (binding.cycleDecoderBtn.visibility != View.VISIBLE) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
binding.cycleDecoderBtn.text = if (player.hwdecActive) "HW" else "SW"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSpeedButton() {
|
|
||||||
binding.cycleSpeedBtn.text = getString(R.string.ui_speed, player.playbackSpeed)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun playPause(view: View) {
|
fun playPause(view: View) {
|
||||||
player.cyclePause()
|
player.cyclePause()
|
||||||
when {
|
binding.playerControls.playPause()
|
||||||
player.paused!! -> animationHandler.removeCallbacks(controlsViewRunnable)
|
|
||||||
binding.controlsView.isVisible -> showGestureView("controls")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val playPauseRunnable = Runnable {
|
private val doubleTapPlayPauseRunnable = Runnable {
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
|
||||||
findViewById<ImageView>(R.id.playPauseView).startAnimation(fadeAnimation)
|
binding.playPauseView.startAnimation(fadeAnimation)
|
||||||
binding.playPauseView.visibility = View.GONE
|
binding.playPauseView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doubleTapPlayPause() {
|
fun doubleTapPlayPause() {
|
||||||
animationHandler.removeCallbacks(playPauseRunnable)
|
animationHandler.removeCallbacks(doubleTapPlayPauseRunnable)
|
||||||
playPause(binding.playBtn)
|
playPause(binding.playerControls.binding.playBtn)
|
||||||
|
|
||||||
if (!binding.controlsView.isVisible) {
|
if (!binding.playerControls.binding.controlsView.isVisible) {
|
||||||
when {
|
when {
|
||||||
player.paused!! -> { binding.playPauseView.setImageResource(R.drawable.ic_pause_80dp) }
|
player.paused!! -> { binding.playPauseView.setImageResource(R.drawable.ic_pause_80dp) }
|
||||||
!player.paused!! -> { binding.playPauseView.setImageResource(R.drawable.ic_play_arrow_80dp) }
|
!player.paused!! -> { binding.playPauseView.setImageResource(R.drawable.ic_play_arrow_80dp) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (binding.controlsView.isVisible) { binding.playPauseView.visibility = View.GONE; binding.playPauseView.setBackgroundColor(0x00000000) } else { binding.playPauseView.visibility = View.VISIBLE; binding.playPauseView.setBackgroundColor(0x70000000) }
|
|
||||||
AnimationUtils.loadAnimation(this, R.anim.fade_in_medium).also { fadeAnimation ->
|
AnimationUtils.loadAnimation(this, R.anim.fade_in_medium).also { fadeAnimation ->
|
||||||
findViewById<ImageView>(R.id.playPauseView).startAnimation(fadeAnimation)
|
binding.playPauseView.startAnimation(fadeAnimation)
|
||||||
binding.playPauseView.visibility = View.VISIBLE
|
binding.playPauseView.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
animationHandler.postDelayed(playPauseRunnable, 500L)
|
animationHandler.postDelayed(doubleTapPlayPauseRunnable, 500L)
|
||||||
} else binding.playPauseView.visibility = View.GONE
|
} else binding.playPauseView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,7 +505,7 @@ class PlayerActivity :
|
||||||
val newDiff = newPos - initialSeek
|
val newDiff = newPos - initialSeek
|
||||||
// seek faster than assigning to timePos but less precise
|
// seek faster than assigning to timePos but less precise
|
||||||
MPVLib.command(arrayOf("seek", newPos.toString(), "absolute+keyframes"))
|
MPVLib.command(arrayOf("seek", newPos.toString(), "absolute+keyframes"))
|
||||||
updatePlaybackPos(newPos)
|
binding.playerControls.updatePlaybackPos(newPos)
|
||||||
|
|
||||||
val diffText = Utils.prettyTime(newDiff, true)
|
val diffText = Utils.prettyTime(newDiff, true)
|
||||||
binding.seekText.text = getString(R.string.ui_seek_distance, Utils.prettyTime(newPos), diffText)
|
binding.seekText.text = getString(R.string.ui_seek_distance, Utils.prettyTime(newPos), diffText)
|
||||||
|
@ -828,13 +593,13 @@ class PlayerActivity :
|
||||||
fun switchDecoder(view: View) {
|
fun switchDecoder(view: View) {
|
||||||
player.cycleHwdec()
|
player.cycleHwdec()
|
||||||
preferences.getPlayerViewMode()
|
preferences.getPlayerViewMode()
|
||||||
updateDecoderButton()
|
binding.playerControls.updateDecoderButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun cycleSpeed(view: View) {
|
fun cycleSpeed(view: View) {
|
||||||
player.cycleSpeed()
|
player.cycleSpeed()
|
||||||
updateSpeedButton()
|
binding.playerControls.updateSpeedButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@ -846,16 +611,16 @@ class PlayerActivity :
|
||||||
// forces update of entire UI, used when resuming the activity
|
// forces update of entire UI, used when resuming the activity
|
||||||
val paused = player.paused ?: return
|
val paused = player.paused ?: return
|
||||||
updatePlaybackStatus(paused)
|
updatePlaybackStatus(paused)
|
||||||
player.timePos?.let { updatePlaybackPos(it) }
|
player.timePos?.let { binding.playerControls.updatePlaybackPos(it) }
|
||||||
player.duration?.let { updatePlaybackDuration(it) }
|
player.duration?.let { binding.playerControls.updatePlaybackDuration(it) }
|
||||||
updatePlaylistButtons()
|
updatePlaylistButtons()
|
||||||
updateEpisodeText()
|
updateEpisodeText()
|
||||||
player.loadTracks()
|
player.loadTracks()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateEpisodeText() {
|
private fun updateEpisodeText() {
|
||||||
binding.titleMainTxt.text = presenter.anime?.title
|
binding.playerControls.binding.titleMainTxt.text = presenter.anime?.title
|
||||||
binding.titleSecondaryTxt.text = presenter.currentEpisode?.name
|
binding.playerControls.binding.titleSecondaryTxt.text = presenter.currentEpisode?.name
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlaylistButtons() {
|
private fun updatePlaylistButtons() {
|
||||||
|
@ -864,13 +629,13 @@ class PlayerActivity :
|
||||||
|
|
||||||
val g = ContextCompat.getColor(this, R.color.tint_disabled)
|
val g = ContextCompat.getColor(this, R.color.tint_disabled)
|
||||||
val w = ContextCompat.getColor(this, R.color.tint_normal)
|
val w = ContextCompat.getColor(this, R.color.tint_normal)
|
||||||
binding.prevBtn.imageTintList = ColorStateList.valueOf(if (plPos == 0) g else w)
|
binding.playerControls.binding.prevBtn.imageTintList = ColorStateList.valueOf(if (plPos == 0) g else w)
|
||||||
binding.nextBtn.imageTintList = ColorStateList.valueOf(if (plPos == plCount - 1) g else w)
|
binding.playerControls.binding.nextBtn.imageTintList = ColorStateList.valueOf(if (plPos == plCount - 1) g else w)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlaybackStatus(paused: Boolean) {
|
private fun updatePlaybackStatus(paused: Boolean) {
|
||||||
val r = if (paused) R.drawable.ic_play_arrow_80dp else R.drawable.ic_pause_80dp
|
val r = if (paused) R.drawable.ic_play_arrow_80dp else R.drawable.ic_pause_80dp
|
||||||
binding.playBtn.setImageResource(r)
|
binding.playerControls.binding.playBtn.setImageResource(r)
|
||||||
|
|
||||||
if (paused) {
|
if (paused) {
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
@ -912,14 +677,14 @@ class PlayerActivity :
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
|
||||||
isInPipMode = isInPictureInPictureMode
|
isInPipMode = isInPictureInPictureMode
|
||||||
hideControls(!isInPictureInPictureMode)
|
binding.playerControls.hideControls(!isInPictureInPictureMode)
|
||||||
if (isInPictureInPictureMode) binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize / 2
|
if (isInPictureInPictureMode) binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize / 2
|
||||||
else binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize * 2
|
else binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize * 2
|
||||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||||
|
|
||||||
if (isInPictureInPictureMode) {
|
if (isInPictureInPictureMode) {
|
||||||
// On Android TV it is required to hide controller in this PIP change callback
|
// On Android TV it is required to hide controller in this PIP change callback
|
||||||
hideControls(true)
|
binding.playerControls.hideControls(true)
|
||||||
mReceiver = object : BroadcastReceiver() {
|
mReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null || ACTION_MEDIA_CONTROL != intent.action) {
|
if (intent == null || ACTION_MEDIA_CONTROL != intent.action) {
|
||||||
|
@ -951,14 +716,14 @@ class PlayerActivity :
|
||||||
unregisterReceiver(mReceiver)
|
unregisterReceiver(mReceiver)
|
||||||
mReceiver = null
|
mReceiver = null
|
||||||
}
|
}
|
||||||
hideControls(false)
|
binding.playerControls.hideControls(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun startPiP() {
|
internal fun startPiP() {
|
||||||
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
hideControls(true)
|
binding.playerControls.hideControls(true)
|
||||||
player.paused?.let { updatePictureInPictureActions(!it) }
|
player.paused?.let { updatePictureInPictureActions(!it) }
|
||||||
?.let { this.enterPictureInPictureMode(it) }
|
?.let { this.enterPictureInPictureMode(it) }
|
||||||
}
|
}
|
||||||
|
@ -1191,8 +956,8 @@ class PlayerActivity :
|
||||||
|
|
||||||
private fun eventPropertyUi(property: String, value: Long) {
|
private fun eventPropertyUi(property: String, value: Long) {
|
||||||
when (property) {
|
when (property) {
|
||||||
"time-pos" -> updatePlaybackPos(value.toInt())
|
"time-pos" -> binding.playerControls.updatePlaybackPos(value.toInt())
|
||||||
"duration" -> updatePlaybackDuration(value.toInt())
|
"duration" -> binding.playerControls.updatePlaybackDuration(value.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1224,3 +989,14 @@ class PlayerActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val ACTION_MEDIA_CONTROL = "media_control"
|
||||||
|
private const val EXTRA_CONTROL_TYPE = "control_type"
|
||||||
|
private const val REQUEST_PLAY = 1
|
||||||
|
private const val REQUEST_PAUSE = 2
|
||||||
|
private const val CONTROL_TYPE_PLAY = 1
|
||||||
|
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
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.player
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.SeekBar
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.PlayerControlsBinding
|
||||||
|
import `is`.xyz.mpv.MPVLib
|
||||||
|
import `is`.xyz.mpv.PickerDialog
|
||||||
|
import `is`.xyz.mpv.SpeedPickerDialog
|
||||||
|
import `is`.xyz.mpv.StateRestoreCallback
|
||||||
|
import `is`.xyz.mpv.Utils
|
||||||
|
|
||||||
|
class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
|
LinearLayout(context, attrs) {
|
||||||
|
|
||||||
|
internal val binding: PlayerControlsBinding =
|
||||||
|
PlayerControlsBinding.inflate(LayoutInflater.from(context), this, false)
|
||||||
|
|
||||||
|
val activity: PlayerActivity = context.getActivity()!!
|
||||||
|
|
||||||
|
private var userIsOperatingSeekbar = false
|
||||||
|
|
||||||
|
private val seekBarChangeListener = object : SeekBar.OnSeekBarChangeListener {
|
||||||
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||||
|
if (!fromUser) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
activity.player.timePos = progress
|
||||||
|
updatePlaybackPos(progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||||
|
userIsOperatingSeekbar = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||||
|
userIsOperatingSeekbar = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun Context.getActivity(): PlayerActivity? = this as? PlayerActivity
|
||||||
|
?: (this as? ContextWrapper)?.baseContext?.getActivity()
|
||||||
|
|
||||||
|
init {
|
||||||
|
addView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewAdded(child: View?) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
binding.pipBtn.isVisible = context.packageManager.hasSystemFeature(
|
||||||
|
PackageManager.FEATURE_PICTURE_IN_PICTURE,
|
||||||
|
) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||||
|
}
|
||||||
|
binding.backArrowBtn.setOnClickListener { activity.finishAndRemoveTask() }
|
||||||
|
binding.pipBtn.setOnClickListener { activity.startPiP() }
|
||||||
|
|
||||||
|
// Lock and Unlock controls
|
||||||
|
binding.lockBtn.setOnClickListener { activity.isLocked = true; toggleControls() }
|
||||||
|
binding.unlockBtn.setOnClickListener { activity.isLocked = false; toggleControls() }
|
||||||
|
|
||||||
|
// Cycle, Long click controls
|
||||||
|
binding.cycleAudioBtn.setOnLongClickListener { pickAudio(); true }
|
||||||
|
binding.cycleSpeedBtn.setOnLongClickListener { pickSpeed(); true }
|
||||||
|
binding.cycleSubsBtn.setOnLongClickListener { pickSub(); true }
|
||||||
|
|
||||||
|
binding.playbackSeekbar.setOnSeekBarChangeListener(seekBarChangeListener)
|
||||||
|
|
||||||
|
binding.nextBtn.setOnClickListener { activity.switchEpisode(false) }
|
||||||
|
binding.prevBtn.setOnClickListener { activity.switchEpisode(true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val animationHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
// Fade out Player controls
|
||||||
|
private val controlsViewRunnable = Runnable {
|
||||||
|
if (activity.isLocked) {
|
||||||
|
fadeOutView(binding.lockedView)
|
||||||
|
} else {
|
||||||
|
fadeOutView(binding.controlsView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun toggleControls() {
|
||||||
|
if (activity.isLocked) {
|
||||||
|
// Hide controls
|
||||||
|
binding.controlsView.isVisible = false
|
||||||
|
|
||||||
|
if (!binding.lockedView.isVisible && !activity.player.paused!!) {
|
||||||
|
showAndFadeControls()
|
||||||
|
} else if (!binding.lockedView.isVisible && activity.player.paused!!) {
|
||||||
|
fadeInView(binding.lockedView)
|
||||||
|
} else {
|
||||||
|
fadeOutView(binding.lockedView)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!binding.controlsView.isVisible && !activity.player.paused!!) {
|
||||||
|
showAndFadeControls()
|
||||||
|
} else if (!binding.controlsView.isVisible && activity.player.paused!!) {
|
||||||
|
fadeInView(binding.controlsView)
|
||||||
|
} else {
|
||||||
|
fadeOutView(binding.controlsView)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.lockedView.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun hideControls(hide: Boolean) {
|
||||||
|
binding.controlsView.isVisible = !hide
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun updatePlaybackPos(position: Int) {
|
||||||
|
binding.playbackPositionTxt.text = Utils.prettyTime(position)
|
||||||
|
if (!userIsOperatingSeekbar) {
|
||||||
|
binding.playbackSeekbar.progress = position
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDecoderButton()
|
||||||
|
updateSpeedButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun updatePlaybackDuration(duration: Int) {
|
||||||
|
binding.playbackDurationTxt.text = Utils.prettyTime(duration)
|
||||||
|
if (!userIsOperatingSeekbar) {
|
||||||
|
binding.playbackSeekbar.max = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun updateDecoderButton() {
|
||||||
|
if (binding.cycleDecoderBtn.visibility != View.VISIBLE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
binding.cycleDecoderBtn.text = if (activity.player.hwdecActive) "HW" else "SW"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun updateSpeedButton() {
|
||||||
|
binding.cycleSpeedBtn.text = context.getString(R.string.ui_speed, activity.player.playbackSpeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun showAndFadeControls() {
|
||||||
|
val itemView = if (!activity.isLocked) binding.controlsView else binding.lockedView
|
||||||
|
animationHandler.removeCallbacks(controlsViewRunnable)
|
||||||
|
itemView.visibility = View.VISIBLE
|
||||||
|
animationHandler.postDelayed(controlsViewRunnable, 3500L)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fadeOutView(view: View) {
|
||||||
|
animationHandler.removeCallbacks(controlsViewRunnable)
|
||||||
|
AnimationUtils.loadAnimation(context, R.anim.fade_out_medium).also { fadeAnimation ->
|
||||||
|
view.startAnimation(fadeAnimation)
|
||||||
|
view.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fadeInView(view: View) {
|
||||||
|
animationHandler.removeCallbacks(controlsViewRunnable)
|
||||||
|
AnimationUtils.loadAnimation(context, R.anim.fade_in_short).also { fadeAnimation ->
|
||||||
|
view.startAnimation(fadeAnimation)
|
||||||
|
view.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pauseForDialog(): StateRestoreCallback {
|
||||||
|
val wasPlayerPaused = activity.player.paused ?: true // default to not changing state
|
||||||
|
activity.player.paused = true
|
||||||
|
return {
|
||||||
|
if (!wasPlayerPaused) {
|
||||||
|
activity.player.paused = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun playPause() {
|
||||||
|
when {
|
||||||
|
activity.player.paused!! -> animationHandler.removeCallbacks(controlsViewRunnable)
|
||||||
|
binding.controlsView.isVisible -> {
|
||||||
|
showAndFadeControls()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pickAudio() {
|
||||||
|
val restore = pauseForDialog()
|
||||||
|
|
||||||
|
with(MaterialAlertDialogBuilder(context)) {
|
||||||
|
setSingleChoiceItems(
|
||||||
|
activity.audioTracks.map { it.lang }.toTypedArray(),
|
||||||
|
activity.selectedAudio,
|
||||||
|
) { dialog, item ->
|
||||||
|
if (item == activity.selectedAudio) return@setSingleChoiceItems
|
||||||
|
if (item == 0) {
|
||||||
|
activity.selectedAudio = 0
|
||||||
|
activity.player.aid = -1
|
||||||
|
return@setSingleChoiceItems
|
||||||
|
}
|
||||||
|
activity.setAudio(item)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
setOnDismissListener { restore() }
|
||||||
|
create().show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pickSub() {
|
||||||
|
val restore = pauseForDialog()
|
||||||
|
|
||||||
|
with(MaterialAlertDialogBuilder(context)) {
|
||||||
|
setSingleChoiceItems(
|
||||||
|
activity.subTracks.map { it.lang }.toTypedArray(),
|
||||||
|
activity.selectedSub,
|
||||||
|
) { dialog, item ->
|
||||||
|
if (item == 0) {
|
||||||
|
activity.selectedSub = 0
|
||||||
|
activity.player.sid = -1
|
||||||
|
return@setSingleChoiceItems
|
||||||
|
}
|
||||||
|
activity.setSub(item)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
setOnDismissListener { restore() }
|
||||||
|
create().show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pickSpeed() {
|
||||||
|
// TODO: replace this with SliderPickerDialog
|
||||||
|
val picker = SpeedPickerDialog()
|
||||||
|
|
||||||
|
val restore = pauseForDialog()
|
||||||
|
speedPickerDialog(picker, R.string.title_speed_dialog) {
|
||||||
|
updateSpeedButton()
|
||||||
|
restore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun speedPickerDialog(
|
||||||
|
picker: PickerDialog,
|
||||||
|
@StringRes titleRes: Int,
|
||||||
|
restoreState: StateRestoreCallback,
|
||||||
|
) {
|
||||||
|
val dialog = with(MaterialAlertDialogBuilder(context)) {
|
||||||
|
setTitle(titleRes)
|
||||||
|
setView(picker.buildView(LayoutInflater.from(context)))
|
||||||
|
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||||
|
picker.number?.let {
|
||||||
|
if (picker.isInteger()) {
|
||||||
|
MPVLib.setPropertyInt("speed", it.toInt())
|
||||||
|
} else {
|
||||||
|
MPVLib.setPropertyDouble("speed", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setNegativeButton(R.string.dialog_cancel) { dialog, _ -> dialog.cancel() }
|
||||||
|
setOnDismissListener { restoreState() }
|
||||||
|
create()
|
||||||
|
}
|
||||||
|
|
||||||
|
picker.number = MPVLib.getPropertyDouble("speed")
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,334 +48,10 @@
|
||||||
app:tint="?attr/colorAccent" />
|
app:tint="?attr/colorAccent" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<eu.kanade.tachiyomi.ui.player.PlayerControlsView
|
||||||
android:id="@+id/lockedView"
|
android:id="@+id/player_controls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"/>
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/unlockBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:contentDescription="Unlock player"
|
|
||||||
android:src="@drawable/ic_lock_open_24dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- Double layout for consistency in code -->
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/controlsView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="#70000000">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
tools:ignore="UselessParent">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/controls_top"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="10dp">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/backArrowBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:contentDescription="Go back"
|
|
||||||
android:src="@drawable/ic_arrow_back_24dp"
|
|
||||||
android:layout_marginHorizontal="10dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/fullTitleTxt"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/fullTitleTxt"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/backArrowBtn"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/cycleDecoderBtn"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleMainTxt"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="?attr/colorOnPrimarySurface"
|
|
||||||
android:text=""
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleSecondaryTxt"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="?attr/colorOnPrimarySurface"
|
|
||||||
android:alpha = "0.5"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:text="" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/settingsBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:contentDescription="Settings"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:onClick="openSettings"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:src="@drawable/ic_settings_24dp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/cycleSubsBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:contentDescription="Subtitles"
|
|
||||||
android:onClick="cycleSub"
|
|
||||||
android:src="@drawable/ic_subtitles_black_24dp"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface"
|
|
||||||
app:layout_constraintRight_toRightOf="@id/cycleAudioBtn"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/settingsBtn"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/cycleAudioBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:contentDescription="Audio"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:onClick="cycleAudio"
|
|
||||||
android:src="@drawable/ic_audiotrack_black_24dp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="@id/cycleDecoderBtn"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/cycleSubsBtn"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/cycleDecoderBtn"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_toLeftOf="@id/cycleAudioBtn"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:onClick="switchDecoder"
|
|
||||||
android:text=".."
|
|
||||||
android:textColor="?attr/colorOnPrimarySurface"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/cycleAudioBtn"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/controls_bottom"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
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"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface"
|
|
||||||
tools:src="@drawable/ic_play_arrow_80dp"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/control_bar"
|
|
||||||
style="?android:attr/buttonBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:orientation="vertical"
|
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/controls_title_group"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="visible">
|
|
||||||
|
|
||||||
<!-- These two are only used for audio -->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleTextView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="-"
|
|
||||||
android:textColor="@color/tint_normal"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/minorTitleTextView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="-"
|
|
||||||
android:textColor="@color/tint_normal"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/lockBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:contentDescription="Lock player"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:src="@drawable/ic_lock_24dp"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/cycleSpeedBtn"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:onClick="cycleSpeed"
|
|
||||||
android:text=".."
|
|
||||||
android:textColor="?attr/colorOnPrimarySurface" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:gravity="right"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/controls_skip_intro_btn"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:onClick="skipIntro"
|
|
||||||
android:text="@string/player_controls_skip_intro_text"
|
|
||||||
android:textColor="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/cycleViewModeBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:contentDescription="Cycle view modes"
|
|
||||||
android:onClick="cycleViewMode"
|
|
||||||
android:src="@drawable/ic_fullscreen_black_24dp"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/pipBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?android:attr/selectableItemBackground"
|
|
||||||
android:contentDescription="@string/action_player_pip"
|
|
||||||
android:src="@drawable/ic_picture_in_picture_24dp"
|
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/controls_seekbar_group"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:weightSum="100">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/prevBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_previous_episode"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
app:srcCompat="@drawable/ic_skip_previous_24dp"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/playbackPositionTxt"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="10"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="0:00"
|
|
||||||
android:textColor="@android:color/white" />
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/playbackSeekbar"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_weight="80"
|
|
||||||
android:progressBackgroundTint="@color/tint_seekbar_bg" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/playbackDurationTxt"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="10"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="0:00"
|
|
||||||
android:textColor="@android:color/white" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/nextBtn"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_next_episode"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
app:srcCompat="@drawable/ic_skip_next_24dp"
|
|
||||||
app:tint="?attr/colorOnPrimarySurface" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</RelativeLayout>
|
|
||||||
</RelativeLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/volumeView"
|
android:id="@+id/volumeView"
|
||||||
|
@ -491,7 +167,7 @@
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:contentDescription="Play/Pause"
|
android:contentDescription="Play/Pause"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:background="#70000000"
|
android:background="#00000000"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:tint="?attr/colorOnPrimarySurface"
|
app:tint="?attr/colorOnPrimarySurface"
|
||||||
tools:src="@drawable/ic_play_arrow_80dp" />
|
tools:src="@drawable/ic_play_arrow_80dp" />
|
||||||
|
|
339
app/src/main/res/layout/player_controls.xml
Normal file
339
app/src/main/res/layout/player_controls.xml
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:ignore="RtlHardcoded,HardcodedText" >
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/lockedView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/unlockBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="Unlock player"
|
||||||
|
android:src="@drawable/ic_lock_open_24dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Double layout for consistency in code -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/controlsView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#70000000">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/controls_top"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/backArrowBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="Go back"
|
||||||
|
android:src="@drawable/ic_arrow_back_24dp"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/fullTitleTxt"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fullTitleTxt"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/backArrowBtn"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/cycleDecoderBtn"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleMainTxt"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/colorOnPrimarySurface"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleSecondaryTxt"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/colorOnPrimarySurface"
|
||||||
|
android:alpha = "0.5"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:text="" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/settingsBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="Settings"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:onClick="openSettings"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:src="@drawable/ic_settings_24dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/cycleSubsBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="Subtitles"
|
||||||
|
android:onClick="cycleSub"
|
||||||
|
android:src="@drawable/ic_subtitles_black_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/cycleAudioBtn"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/settingsBtn"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/cycleAudioBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="Audio"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:onClick="cycleAudio"
|
||||||
|
android:src="@drawable/ic_audiotrack_black_24dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/cycleDecoderBtn"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/cycleSubsBtn"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cycleDecoderBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_toLeftOf="@id/cycleAudioBtn"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:onClick="switchDecoder"
|
||||||
|
android:text=".."
|
||||||
|
android:textColor="?attr/colorOnPrimarySurface"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/cycleAudioBtn"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/controls_bottom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
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"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface"
|
||||||
|
tools:src="@drawable/ic_play_arrow_80dp"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/control_bar"
|
||||||
|
style="?android:attr/buttonBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/controls_title_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<!-- These two are only used for audio -->
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="-"
|
||||||
|
android:textColor="@color/tint_normal"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/minorTitleTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="-"
|
||||||
|
android:textColor="@color/tint_normal"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/lockBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:contentDescription="Lock player"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_lock_24dp"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cycleSpeedBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:onClick="cycleSpeed"
|
||||||
|
android:text=".."
|
||||||
|
android:textColor="?attr/colorOnPrimarySurface" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:gravity="right"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/controls_skip_intro_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:onClick="skipIntro"
|
||||||
|
android:text="@string/player_controls_skip_intro_text"
|
||||||
|
android:textColor="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/cycleViewModeBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="Cycle view modes"
|
||||||
|
android:onClick="cycleViewMode"
|
||||||
|
android:src="@drawable/ic_fullscreen_black_24dp"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/pipBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/action_player_pip"
|
||||||
|
android:src="@drawable/ic_picture_in_picture_24dp"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/controls_seekbar_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="100">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/prevBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/action_previous_episode"
|
||||||
|
android:padding="@dimen/screen_edge_margin"
|
||||||
|
app:srcCompat="@drawable/ic_skip_previous_24dp"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackPositionTxt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="10"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="0:00"
|
||||||
|
android:textColor="@android:color/white" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/playbackSeekbar"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="80"
|
||||||
|
android:progressBackgroundTint="@color/tint_seekbar_bg" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackDurationTxt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="10"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="0:00"
|
||||||
|
android:textColor="@android:color/white" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/nextBtn"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/action_next_episode"
|
||||||
|
android:padding="@dimen/screen_edge_margin"
|
||||||
|
app:srcCompat="@drawable/ic_skip_next_24dp"
|
||||||
|
app:tint="?attr/colorOnPrimarySurface" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
Loading…
Reference in a new issue