mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-13 22:00:30 +05:30
Merge pull request #5641 from Bnyro/master
feat(player): support for keyboard navigation
This commit is contained in:
commit
ce8ed66e92
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.KeyEvent
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -138,12 +139,7 @@ class MainActivity : BaseActivity() {
|
|||||||
// new way of handling back presses
|
// new way of handling back presses
|
||||||
onBackPressedDispatcher.addCallback {
|
onBackPressedDispatcher.addCallback {
|
||||||
if (playerViewModel.isFullscreen.value == true) {
|
if (playerViewModel.isFullscreen.value == true) {
|
||||||
supportFragmentManager.fragments.filterIsInstance<PlayerFragment>()
|
runOnPlayerFragment { unsetFullscreen() }
|
||||||
.firstOrNull()
|
|
||||||
?.let {
|
|
||||||
it.unsetFullscreen()
|
|
||||||
return@addCallback
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binding.mainMotionLayout.progress == 0F) {
|
if (binding.mainMotionLayout.progress == 0F) {
|
||||||
@ -490,9 +486,8 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onUserLeaveHint() {
|
override fun onUserLeaveHint() {
|
||||||
super.onUserLeaveHint()
|
super.onUserLeaveHint()
|
||||||
supportFragmentManager.fragments.forEach { fragment ->
|
|
||||||
(fragment as? PlayerFragment)?.onUserLeaveHint()
|
runOnPlayerFragment { onUserLeaveHint() }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent?) {
|
||||||
@ -500,4 +495,14 @@ class MainActivity : BaseActivity() {
|
|||||||
this.intent = intent
|
this.intent = intent
|
||||||
loadIntentData()
|
loadIntentData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
return runOnPlayerFragment { onKeyUp(keyCode, event) } ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> runOnPlayerFragment(action: PlayerFragment.() -> T): T? {
|
||||||
|
return supportFragmentManager.fragments.filterIsInstance<PlayerFragment>()
|
||||||
|
.firstOrNull()
|
||||||
|
?.let(action)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import android.media.session.PlaybackState
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
|
import android.view.KeyEvent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@ -231,4 +232,8 @@ class OfflinePlayerActivity : BaseActivity() {
|
|||||||
|
|
||||||
super.onUserLeaveHint()
|
super.onUserLeaveHint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
return binding.player.onKeyBoardAction(keyCode, event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,15 +123,11 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.prev.setOnClickListener {
|
binding.prev.setOnClickListener {
|
||||||
val currentIndex = PlayingQueue.currentIndex()
|
PlayingQueue.navigatePrev()
|
||||||
if (!PlayingQueue.hasPrev()) return@setOnClickListener
|
|
||||||
PlayingQueue.onQueueItemSelected(currentIndex - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.next.setOnClickListener {
|
binding.next.setOnClickListener {
|
||||||
val currentIndex = PlayingQueue.currentIndex()
|
PlayingQueue.navigateNext()
|
||||||
if (!PlayingQueue.hasNext()) return@setOnClickListener
|
|
||||||
PlayingQueue.onQueueItemSelected(currentIndex + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listOf(binding.forwardTV, binding.rewindTV).forEach {
|
listOf(binding.forwardTV, binding.rewindTV).forEach {
|
||||||
|
@ -15,6 +15,7 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
|
import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -190,6 +191,10 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
unsetFullscreen()
|
unsetFullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
|
return _binding?.player?.onKeyUp(keyCode, event) ?: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,19 +540,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
// FullScreen button trigger
|
// FullScreen button trigger
|
||||||
// hide fullscreen button if autorotation enabled
|
// hide fullscreen button if autorotation enabled
|
||||||
playerBinding.fullscreen.setOnClickListener {
|
playerBinding.fullscreen.setOnClickListener {
|
||||||
// hide player controller
|
toggleFullscreen()
|
||||||
binding.player.hideController()
|
|
||||||
if (viewModel.isFullscreen.value == false) {
|
|
||||||
// go to fullscreen mode
|
|
||||||
setFullscreen()
|
|
||||||
} else {
|
|
||||||
// exit fullscreen mode
|
|
||||||
unsetFullscreen()
|
|
||||||
|
|
||||||
// disable the fullscreen button for auto fullscreen
|
|
||||||
// this is necessary to hide the button after an auto fullscreen for shorts
|
|
||||||
playerBinding.fullscreen.isVisible = !PlayerHelper.autoFullscreenEnabled
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val updateSbImageResource = {
|
val updateSbImageResource = {
|
||||||
@ -732,6 +725,25 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
binding.player.updateMarginsByFullscreenMode()
|
binding.player.updateMarginsByFullscreenMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable fullscreen depending on the current state
|
||||||
|
*/
|
||||||
|
fun toggleFullscreen() {
|
||||||
|
// hide player controller
|
||||||
|
binding.player.hideController()
|
||||||
|
if (viewModel.isFullscreen.value == false) {
|
||||||
|
// go to fullscreen mode
|
||||||
|
setFullscreen()
|
||||||
|
} else {
|
||||||
|
// exit fullscreen mode
|
||||||
|
unsetFullscreen()
|
||||||
|
|
||||||
|
// disable the fullscreen button for auto fullscreen
|
||||||
|
// this is necessary to hide the button after an auto fullscreen for shorts
|
||||||
|
playerBinding.fullscreen.isVisible = !PlayerHelper.autoFullscreenEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun openOrCloseFullscreenDialog(open: Boolean) {
|
private fun openOrCloseFullscreenDialog(open: Boolean) {
|
||||||
val playerView = binding.player
|
val playerView = binding.player
|
||||||
(playerView.parent as ViewGroup).removeView(playerView)
|
(playerView.parent as ViewGroup).removeView(playerView)
|
||||||
@ -1690,4 +1702,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
binding.player.useController = false
|
binding.player.useController = false
|
||||||
binding.player.hideController()
|
binding.player.hideController()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
return _binding?.player?.onKeyBoardAction(keyCode, event) ?: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
@ -23,6 +24,7 @@ import androidx.core.view.isGone
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.marginStart
|
import androidx.core.view.marginStart
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.fragment.app.commit
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.common.text.Cue
|
import androidx.media3.common.text.Cue
|
||||||
@ -44,6 +46,7 @@ import com.github.libretube.extensions.seekBy
|
|||||||
import com.github.libretube.extensions.togglePlayPauseState
|
import com.github.libretube.extensions.togglePlayPauseState
|
||||||
import com.github.libretube.helpers.AudioHelper
|
import com.github.libretube.helpers.AudioHelper
|
||||||
import com.github.libretube.helpers.BrightnessHelper
|
import com.github.libretube.helpers.BrightnessHelper
|
||||||
|
import com.github.libretube.helpers.ContextHelper
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
import com.github.libretube.helpers.WindowHelper
|
import com.github.libretube.helpers.WindowHelper
|
||||||
@ -51,6 +54,7 @@ import com.github.libretube.obj.BottomSheetItem
|
|||||||
import com.github.libretube.ui.base.BaseActivity
|
import com.github.libretube.ui.base.BaseActivity
|
||||||
import com.github.libretube.ui.extensions.toggleSystemBars
|
import com.github.libretube.ui.extensions.toggleSystemBars
|
||||||
import com.github.libretube.ui.extensions.trySetTooltip
|
import com.github.libretube.ui.extensions.trySetTooltip
|
||||||
|
import com.github.libretube.ui.fragments.PlayerFragment
|
||||||
import com.github.libretube.ui.interfaces.PlayerGestureOptions
|
import com.github.libretube.ui.interfaces.PlayerGestureOptions
|
||||||
import com.github.libretube.ui.interfaces.PlayerOptions
|
import com.github.libretube.ui.interfaces.PlayerOptions
|
||||||
import com.github.libretube.ui.listeners.PlayerGestureController
|
import com.github.libretube.ui.listeners.PlayerGestureController
|
||||||
@ -729,6 +733,34 @@ open class CustomExoPlayerView(
|
|||||||
return super.onInterceptTouchEvent(ev)
|
return super.onInterceptTouchEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onKeyBoardAction(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
when (keyCode) {
|
||||||
|
KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
|
||||||
|
player?.togglePlayPauseState()
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {
|
||||||
|
forward()
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_MEDIA_REWIND -> {
|
||||||
|
rewind()
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_NAVIGATE_NEXT -> {
|
||||||
|
PlayingQueue.navigateNext()
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_NAVIGATE_PREVIOUS -> {
|
||||||
|
PlayingQueue.navigatePrev()
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_F -> {
|
||||||
|
val fragmentManager = ContextHelper.unwrapActivity(context).supportFragmentManager
|
||||||
|
fragmentManager.fragments.filterIsInstance<PlayerFragment>().firstOrNull()
|
||||||
|
?.toggleFullscreen()
|
||||||
|
}
|
||||||
|
else -> super.onKeyUp(keyCode, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
open fun minimizeOrExitPlayer() = Unit
|
open fun minimizeOrExitPlayer() = Unit
|
||||||
|
|
||||||
open fun getWindow(): Window = activity.window
|
open fun getWindow(): Window = activity.window
|
||||||
|
@ -279,15 +279,11 @@ class NowPlayingNotification(
|
|||||||
private fun handlePlayerAction(action: String) {
|
private fun handlePlayerAction(action: String) {
|
||||||
when (action) {
|
when (action) {
|
||||||
NEXT -> {
|
NEXT -> {
|
||||||
if (!PlayingQueue.hasNext()) return
|
PlayingQueue.navigateNext()
|
||||||
|
|
||||||
PlayingQueue.onQueueItemSelected(PlayingQueue.currentIndex() + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PREV -> {
|
PREV -> {
|
||||||
if (!PlayingQueue.hasPrev()) return
|
PlayingQueue.navigatePrev()
|
||||||
|
|
||||||
PlayingQueue.onQueueItemSelected(PlayingQueue.currentIndex() - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
REWIND -> {
|
REWIND -> {
|
||||||
|
@ -222,6 +222,18 @@ object PlayingQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun navigatePrev() {
|
||||||
|
if (!hasPrev()) return
|
||||||
|
|
||||||
|
onQueueItemSelected(currentIndex() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun navigateNext() {
|
||||||
|
if (!hasNext()) return
|
||||||
|
|
||||||
|
onQueueItemSelected(currentIndex() + 1)
|
||||||
|
}
|
||||||
|
|
||||||
fun setOnQueueTapListener(listener: (StreamItem) -> Unit) {
|
fun setOnQueueTapListener(listener: (StreamItem) -> Unit) {
|
||||||
onQueueTapListener = listener
|
onQueueTapListener = listener
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user