mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 14:20:30 +05:30
Merge pull request #4981 from Bnyro/landscape-player-page
feat: landscape layout for player page
This commit is contained in:
commit
fc9e3e6501
@ -1,15 +1,14 @@
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.github.libretube.ui.extensions.toggleSystemBars
|
||||
|
||||
object WindowHelper {
|
||||
fun toggleFullscreen(activity: Activity, isFullscreen: Boolean) {
|
||||
val window = activity.window
|
||||
fun toggleFullscreen(window: Window, isFullscreen: Boolean) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
window.attributes.layoutInDisplayCutoutMode = if (isFullscreen) {
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
@ -30,7 +29,7 @@ object WindowHelper {
|
||||
// Show the system bars when it is not fullscreen and hide them when it is fullscreen
|
||||
// System bars means status bar and the navigation bar
|
||||
// See: https://developer.android.com/training/system-ui/immersive#kotlin
|
||||
activity.toggleSystemBars(
|
||||
window.toggleSystemBars(
|
||||
types = WindowInsetsCompat.Type.systemBars(),
|
||||
showBars = !isFullscreen
|
||||
)
|
||||
|
@ -486,8 +486,8 @@ class MainActivity : BaseActivity() {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
when (newConfig.orientation) {
|
||||
Configuration.ORIENTATION_PORTRAIT -> WindowHelper.toggleFullscreen(this, false)
|
||||
Configuration.ORIENTATION_LANDSCAPE -> WindowHelper.toggleFullscreen(this, true)
|
||||
Configuration.ORIENTATION_PORTRAIT -> WindowHelper.toggleFullscreen(window, false)
|
||||
Configuration.ORIENTATION_LANDSCAPE -> WindowHelper.toggleFullscreen(window, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class OfflinePlayerActivity : BaseActivity() {
|
||||
private val playerViewModel: PlayerViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
WindowHelper.toggleFullscreen(this, true)
|
||||
WindowHelper.toggleFullscreen(window, true)
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
|
||||
|
@ -13,7 +13,7 @@ import com.github.libretube.helpers.ThemeHelper
|
||||
* Activity that applies the LibreTube theme and the in-app language
|
||||
*/
|
||||
open class BaseActivity : AppCompatActivity() {
|
||||
private val screenOrientationPref by lazy {
|
||||
val screenOrientationPref by lazy {
|
||||
val orientationPref = PreferenceHelper.getString(
|
||||
PreferenceKeys.ORIENTATION,
|
||||
resources.getString(R.string.config_default_orientation_pref)
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.github.libretube.ui.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.Window
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat.Type.InsetsType
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
|
||||
fun Activity.toggleSystemBars(@InsetsType types: Int, showBars: Boolean) {
|
||||
WindowCompat.getInsetsController(window, window.decorView).apply {
|
||||
fun Window.toggleSystemBars(@InsetsType types: Int, showBars: Boolean) {
|
||||
WindowCompat.getInsetsController(this, decorView).apply {
|
||||
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
if (showBars) {
|
||||
show(types)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.libretube.ui.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -17,7 +18,9 @@ import android.text.format.DateUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import android.widget.Toast
|
||||
import android.window.OnBackInvokedDispatcher
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.constraintlayout.motion.widget.TransitionAdapter
|
||||
import androidx.core.content.getSystemService
|
||||
@ -85,12 +88,14 @@ import com.github.libretube.helpers.PlayerHelper.getVideoStats
|
||||
import com.github.libretube.helpers.PlayerHelper.isInSegment
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
import com.github.libretube.helpers.WindowHelper
|
||||
import com.github.libretube.obj.PlayerNotificationData
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.obj.VideoResolution
|
||||
import com.github.libretube.parcelable.PlayerData
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.dialogs.AddToPlaylistDialog
|
||||
import com.github.libretube.ui.dialogs.DownloadDialog
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
@ -188,6 +193,21 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
private var scrubbingTimeBar = false
|
||||
private var chaptersBottomSheet: ChaptersBottomSheet? = null
|
||||
|
||||
/**
|
||||
* The orientation of the `fragment_player.xml` that's currently used
|
||||
* This is needed in order to figure out if the current layout is the landscape one or not.
|
||||
*/
|
||||
private var playerLayoutOrientation = Int.MIN_VALUE
|
||||
|
||||
private val fullscreenDialog by lazy {
|
||||
object: Dialog(requireContext(), android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
|
||||
override fun onBackPressed() {
|
||||
super.onBackPressed()
|
||||
unsetFullscreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receiver for all actions in the PiP mode
|
||||
*/
|
||||
@ -236,6 +256,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
keepQueue = playerData.keepQueue
|
||||
timeStamp = playerData.timestamp
|
||||
|
||||
playerLayoutOrientation = resources.configuration.orientation
|
||||
|
||||
// broadcast receiver for PiP actions
|
||||
context?.registerReceiver(
|
||||
broadcastReceiver,
|
||||
@ -365,17 +387,19 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
.isPictureInPictureAvailable(activity)
|
||||
}
|
||||
|
||||
// actions that don't depend on video information
|
||||
private fun initializeOnClickActions() {
|
||||
binding.closeImageView.setOnClickListener {
|
||||
private fun onManualPlayerClose() {
|
||||
PlayingQueue.clear()
|
||||
BackgroundHelper.stopBackgroundPlay(requireContext())
|
||||
killPlayerFragment()
|
||||
}
|
||||
|
||||
// actions that don't depend on video information
|
||||
private fun initializeOnClickActions() {
|
||||
binding.closeImageView.setOnClickListener {
|
||||
onManualPlayerClose()
|
||||
}
|
||||
playerBinding.closeImageButton.setOnClickListener {
|
||||
PlayingQueue.clear()
|
||||
BackgroundHelper.stopBackgroundPlay(requireContext())
|
||||
killPlayerFragment()
|
||||
onManualPlayerClose()
|
||||
}
|
||||
playerBinding.autoPlay.isVisible = true
|
||||
|
||||
@ -499,50 +523,30 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
NavigationHelper.startAudioPlayer(requireContext())
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled, determine the orientation o use based on the video's aspect ratio
|
||||
* Expected behavior: Portrait for shorts, Landscape for normal videos
|
||||
*/
|
||||
private fun updateFullscreenOrientation() {
|
||||
if (!PlayerHelper.autoFullscreenEnabled) {
|
||||
val height = streams.videoStreams.firstOrNull()?.height ?: exoPlayer.videoSize.height
|
||||
val width = streams.videoStreams.firstOrNull()?.width ?: exoPlayer.videoSize.width
|
||||
|
||||
// different orientations of the video are only available when autorotation is disabled
|
||||
val orientation = PlayerHelper.getOrientation(width, height)
|
||||
mainActivity.requestedOrientation = orientation
|
||||
}
|
||||
}
|
||||
|
||||
private fun setFullscreen() {
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, -1)
|
||||
enableTransition(R.id.yt_transition, false)
|
||||
}
|
||||
|
||||
// set status bar icon color to white
|
||||
windowInsetsControllerCompat.isAppearanceLightStatusBars = false
|
||||
|
||||
binding.mainContainer.isClickable = true
|
||||
binding.linLayout.isGone = true
|
||||
viewModel.isFullscreen.value = true
|
||||
|
||||
if (mainActivity.screenOrientationPref == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT) {
|
||||
val height = streams.videoStreams.firstOrNull()?.height ?: exoPlayer.videoSize.height
|
||||
val width = streams.videoStreams.firstOrNull()?.width ?: exoPlayer.videoSize.width
|
||||
|
||||
mainActivity.requestedOrientation = PlayerHelper.getOrientation(width, height)
|
||||
}
|
||||
|
||||
commentsViewModel.setCommentSheetExpand(null)
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen_exit)
|
||||
playerBinding.exoTitle.isVisible = true
|
||||
|
||||
updateFullscreenOrientation()
|
||||
viewModel.isFullscreen.value = true
|
||||
|
||||
updateResolutionOnFullscreenChange(true)
|
||||
|
||||
openOrCloseFullscreenDialog(true)
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
fun unsetFullscreen() {
|
||||
// leave fullscreen mode
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
||||
enableTransition(R.id.yt_transition, true)
|
||||
}
|
||||
|
||||
// set status bar icon color back to theme color
|
||||
windowInsetsControllerCompat.isAppearanceLightStatusBars =
|
||||
when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||
@ -551,19 +555,40 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
else -> true
|
||||
}
|
||||
|
||||
binding.mainContainer.isClickable = false
|
||||
binding.linLayout.isVisible = true
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
||||
playerBinding.exoTitle.isInvisible = true
|
||||
viewModel.isFullscreen.value = false
|
||||
|
||||
if (!PlayerHelper.autoFullscreenEnabled) {
|
||||
// switch back to portrait mode if autorotation disabled
|
||||
if (mainActivity.screenOrientationPref == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT) {
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
}
|
||||
|
||||
viewModel.isFullscreen.value = false
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
||||
playerBinding.exoTitle.isInvisible = true
|
||||
|
||||
updateResolutionOnFullscreenChange(false)
|
||||
|
||||
openOrCloseFullscreenDialog(false)
|
||||
|
||||
checkForNecessaryOrientationRestart()
|
||||
}
|
||||
|
||||
private fun openOrCloseFullscreenDialog(open: Boolean) {
|
||||
val playerView = binding.player
|
||||
(playerView.parent as ViewGroup).removeView(playerView)
|
||||
|
||||
if (open) {
|
||||
fullscreenDialog.addContentView(
|
||||
binding.player,
|
||||
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
)
|
||||
fullscreenDialog.show()
|
||||
playerView.currentWindow = fullscreenDialog.window
|
||||
} else {
|
||||
binding.playerMotionLayout.addView(playerView)
|
||||
playerView.currentWindow = null
|
||||
fullscreenDialog.dismiss()
|
||||
}
|
||||
|
||||
WindowHelper.toggleFullscreen(fullscreenDialog.window!!, open)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@ -735,8 +760,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
initializePlayerView()
|
||||
setupSeekbarPreview()
|
||||
|
||||
if (viewModel.isFullscreen.value == true) updateFullscreenOrientation()
|
||||
|
||||
exoPlayer.playWhenReady = PlayerHelper.playAutomatically
|
||||
exoPlayer.prepare()
|
||||
|
||||
@ -1341,7 +1364,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
onConfigurationChanged(resources.configuration)
|
||||
} else {
|
||||
// go to portrait mode
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
mainActivity.requestedOrientation = (requireActivity() as BaseActivity).screenOrientationPref
|
||||
}
|
||||
}
|
||||
|
||||
@ -1470,13 +1493,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
viewModel.isMiniPlayerVisible.value = false
|
||||
}
|
||||
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, -1)
|
||||
enableTransition(R.id.yt_transition, false)
|
||||
}
|
||||
binding.linLayout.isGone = true
|
||||
|
||||
updateCurrentSubtitle(null)
|
||||
|
||||
openOrCloseFullscreenDialog(true)
|
||||
} else {
|
||||
// close button got clicked in PiP mode
|
||||
// pause the video and keep the app alive
|
||||
@ -1485,20 +1504,13 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
// enable exoPlayer controls again
|
||||
binding.player.useController = true
|
||||
|
||||
// set back to portrait mode
|
||||
if (viewModel.isFullscreen.value != true) {
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
||||
enableTransition(R.id.yt_transition, true)
|
||||
}
|
||||
binding.linLayout.isVisible = true
|
||||
}
|
||||
|
||||
updateCurrentSubtitle(currentSubtitle)
|
||||
|
||||
binding.optionsLL.post {
|
||||
binding.optionsLL.requestLayout()
|
||||
}
|
||||
|
||||
openOrCloseFullscreenDialog(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1564,6 +1576,12 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
private fun killPlayerFragment() {
|
||||
viewModel.isFullscreen.value = false
|
||||
viewModel.isMiniPlayerVisible.value = false
|
||||
|
||||
// dismiss the fullscreen dialog if it's currently visible
|
||||
// otherwise it would stay alive while being detached from this fragment
|
||||
fullscreenDialog.dismiss()
|
||||
binding.player.currentWindow = null
|
||||
|
||||
binding.playerMotionLayout.transitionToEnd()
|
||||
mainActivity.supportFragmentManager.commit {
|
||||
remove(this@PlayerFragment)
|
||||
@ -1572,21 +1590,43 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
onDestroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the activity needs to be recreated due to an orientation change
|
||||
* If true, the activity will be automatically restarted
|
||||
*/
|
||||
private fun checkForNecessaryOrientationRestart() {
|
||||
val lockedOrientations = listOf(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
|
||||
if (mainActivity.screenOrientationPref in lockedOrientations) return
|
||||
|
||||
val orientation = resources.configuration.orientation
|
||||
if (viewModel.isFullscreen.value != true && orientation != playerLayoutOrientation) {
|
||||
if (this::exoPlayer.isInitialized) {
|
||||
arguments?.putLong(IntentData.timeStamp, exoPlayer.currentPosition / 1000)
|
||||
}
|
||||
playerLayoutOrientation = orientation
|
||||
activity?.recreate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
if (!PlayerHelper.autoFullscreenEnabled || _binding == null ||
|
||||
if (_binding == null ||
|
||||
// If in PiP mode, orientation is given as landscape.
|
||||
PictureInPictureCompat.isInPictureInPictureMode(requireActivity())
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (PlayerHelper.autoFullscreenEnabled) {
|
||||
when (newConfig.orientation) {
|
||||
// go to fullscreen mode
|
||||
Configuration.ORIENTATION_LANDSCAPE -> setFullscreen()
|
||||
// exit fullscreen if not landscape
|
||||
else -> unsetFullscreen()
|
||||
}
|
||||
} else {
|
||||
checkForNecessaryOrientationRestart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,19 +39,6 @@ class CommentsSheet : UndimmedBottomSheet() {
|
||||
|
||||
val binding = binding
|
||||
|
||||
binding.dragHandle.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
binding.dragHandle.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
|
||||
// limit the recyclerview height to not cover the video
|
||||
binding.standardBottomSheet.layoutParams =
|
||||
binding.commentFragContainer.layoutParams.apply {
|
||||
height = playerViewModel.maxSheetHeightPx
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
binding.btnBack.setOnClickListener {
|
||||
if (childFragmentManager.backStackEntryCount > 0) {
|
||||
childFragmentManager.popBackStack()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.libretube.ui.sheets
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
@ -21,11 +22,13 @@ abstract class UndimmedBottomSheet : ExpandedBottomSheet() {
|
||||
override fun onGlobalLayout() {
|
||||
getDragHandle().viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
|
||||
if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
// limit the recyclerview height to not cover the video
|
||||
getBottomSheet().updateLayoutParams {
|
||||
height = getSheetMaxHeightPx()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import android.text.format.DateUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
@ -87,6 +88,12 @@ open class CustomExoPlayerView(
|
||||
updateCurrentPosition()
|
||||
}
|
||||
|
||||
/**
|
||||
* The window that needs to be addressed for showing and hiding the system bars
|
||||
* If null, the activity's default/main window will be used
|
||||
*/
|
||||
var currentWindow: Window? = null
|
||||
|
||||
/**
|
||||
* Preferences
|
||||
*/
|
||||
@ -143,7 +150,7 @@ open class CustomExoPlayerView(
|
||||
// change locked status
|
||||
isPlayerLocked = !isPlayerLocked
|
||||
|
||||
activity.toggleSystemBars(
|
||||
(currentWindow ?: activity.window).toggleSystemBars(
|
||||
types = WindowInsetsCompat.Type.statusBars(),
|
||||
showBars = !isPlayerLocked
|
||||
)
|
||||
|
@ -13,13 +13,13 @@ class OfflinePlayerView(
|
||||
override fun hideController() {
|
||||
super.hideController()
|
||||
// hide the status bars when continuing to watch video
|
||||
activity.toggleSystemBars(WindowInsetsCompat.Type.systemBars(), false)
|
||||
activity.window.toggleSystemBars(WindowInsetsCompat.Type.systemBars(), false)
|
||||
}
|
||||
|
||||
override fun showController() {
|
||||
super.showController()
|
||||
// show status bar when showing player options
|
||||
activity.toggleSystemBars(WindowInsetsCompat.Type.statusBars(), true)
|
||||
activity.window.toggleSystemBars(WindowInsetsCompat.Type.statusBars(), true)
|
||||
}
|
||||
|
||||
override fun getTopBarMarginDp(): Int {
|
||||
|
@ -145,7 +145,7 @@ class OnlinePlayerView(
|
||||
this.playerOptions = playerOptions
|
||||
|
||||
playerViewModel.isFullscreen.observe(viewLifecycleOwner) { isFullscreen ->
|
||||
WindowHelper.toggleFullscreen(activity, isFullscreen)
|
||||
WindowHelper.toggleFullscreen(activity.window, isFullscreen)
|
||||
updateTopBarMargin()
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ class OnlinePlayerView(
|
||||
playerViewModel.isFullscreen.value?.let { isFullscreen ->
|
||||
if (!isFullscreen) return@let
|
||||
// Show status bar only not navigation bar if the player controls are visible and hide it otherwise
|
||||
activity.toggleSystemBars(
|
||||
activity.window.toggleSystemBars(
|
||||
types = WindowInsetsCompat.Type.statusBars(),
|
||||
showBars = visibility == View.VISIBLE && !isPlayerLocked
|
||||
)
|
||||
@ -189,7 +189,7 @@ class OnlinePlayerView(
|
||||
super.hideController()
|
||||
|
||||
if (playerViewModel?.isFullscreen?.value == true) {
|
||||
WindowHelper.toggleFullscreen(activity, true)
|
||||
WindowHelper.toggleFullscreen(activity.window, true)
|
||||
}
|
||||
updateTopBarMargin()
|
||||
}
|
||||
|
312
app/src/main/res/layout-land/fragment_player.xml
Normal file
312
app/src/main/res/layout-land/fragment_player.xml
Normal file
@ -0,0 +1,312 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.github.libretube.ui.views.SingleViewTouchableMotionLayout 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:id="@+id/playerMotionLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutDescription="@xml/player_scene">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/player_scrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:attr/colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/related_container"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/main_container">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.github.libretube.ui.views.DescriptionLayout
|
||||
android:id="@+id/descriptionLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/Widget.Material3.CardView.Elevated"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_marginVertical="17dp"
|
||||
app:cardCornerRadius="27dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/optionsLL"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginVertical="18dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/relPlayer_share"
|
||||
style="@style/PlayerActionsText"
|
||||
android:text="@string/share"
|
||||
app:drawableTopCompat="@drawable/ic_share" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/relPlayer_download"
|
||||
style="@style/PlayerActionsText"
|
||||
android:text="@string/download"
|
||||
app:drawableTopCompat="@drawable/ic_download" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/relPlayer_pip"
|
||||
style="@style/PlayerActionsText"
|
||||
android:text="@string/pop_up"
|
||||
app:drawableTopCompat="@drawable/ic_open" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/relPlayer_background"
|
||||
style="@style/PlayerActionsText"
|
||||
android:text="@string/audio"
|
||||
app:drawableTopCompat="@drawable/ic_headphones" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/relPlayer_save"
|
||||
style="@style/PlayerActionsText"
|
||||
android:text="@string/save"
|
||||
app:drawableTopCompat="@drawable/ic_save" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_channel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:background="@drawable/rounded_ripple"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dp">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/player_channelImage"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:shapeAppearance="@style/CircleImageView" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:layoutDirection="locale"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_channelName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_channelSubCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="11sp"
|
||||
tools:text="2.5M subscribers" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/player_subscribe"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/subscribe"
|
||||
android:textColor="?colorControlNormal"
|
||||
android:textSize="12sp"
|
||||
app:cornerRadius="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/alternativeTrendingRec"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/comments_toggle"
|
||||
style="@style/Widget.Material3.CardView.Elevated"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="16dp"
|
||||
app:cardCornerRadius="18dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@string/comments"
|
||||
android:textAlignment="viewStart"
|
||||
app:drawableEndCompat="@drawable/ic_arrow_up_down" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/main_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_constraintDimensionRatio="16:9"
|
||||
app:layout_constraintWidth_percent=".55"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/related_container"
|
||||
app:layout_constraintWidth_default="percent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/related_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/main_container"
|
||||
android:background="?android:windowBackground">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/related_rec_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
</RelativeLayout>
|
||||
|
||||
<com.github.libretube.ui.views.OnlinePlayerView
|
||||
android:id="@+id/player"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@android:color/black"
|
||||
app:controller_layout_id="@layout/exo_styled_player_control_view"
|
||||
app:layout_constraintBottom_toBottomOf="@id/main_container"
|
||||
app:layout_constraintStart_toStartOf="@id/main_container"
|
||||
app:layout_constraintTop_toTopOf="@id/main_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/main_container"
|
||||
app:show_buffering="when_playing">
|
||||
|
||||
<com.github.libretube.ui.views.DoubleTapOverlay
|
||||
android:id="@+id/doubleTapOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center" />
|
||||
|
||||
<com.github.libretube.ui.views.PlayerGestureControlsView
|
||||
android:id="@+id/playerGestureControlsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|end"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginEnd="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
app:cardBackgroundColor="#88000000"
|
||||
app:strokeWidth="1dp"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/sb_skip_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="20dp"
|
||||
android:padding="10dp"
|
||||
android:text="@string/skip_segment"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone"
|
||||
app:drawableEndCompat="@drawable/ic_next"
|
||||
app:drawableEndDimen="20dp"
|
||||
app:drawableTint="@android:color/white" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.github.libretube.ui.views.AutoplayCountdownView
|
||||
android:id="@+id/autoplay_countdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
</com.github.libretube.ui.views.OnlinePlayerView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close_imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_close"
|
||||
android:tooltipText="@string/tooltip_close"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/main_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/main_container"
|
||||
app:layout_constraintTop_toTopOf="@id/main_container" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_play"
|
||||
android:tooltipText="@string/tooltip_play"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/close_imageView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/close_imageView"
|
||||
app:layout_constraintTop_toTopOf="@+id/close_imageView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_textView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:paddingVertical="15dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/play_imageView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/play_imageView"
|
||||
app:layout_constraintStart_toEndOf="@+id/player"
|
||||
app:layout_constraintTop_toTopOf="@+id/play_imageView" />
|
||||
|
||||
</com.github.libretube.ui.views.SingleViewTouchableMotionLayout>
|
@ -33,9 +33,10 @@
|
||||
<ConstraintSet android:id="@+id/start">
|
||||
<Constraint
|
||||
android:id="@+id/player"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
motion:layout_constraintBottom_toBottomOf="@id/main_container"
|
||||
motion:layout_constraintEnd_toEndOf="@id/main_container"
|
||||
motion:layout_constraintStart_toStartOf="@id/main_container"
|
||||
motion:layout_constraintTop_toTopOf="@id/main_container" />
|
||||
<Constraint android:id="@+id/doubleTapOverlay" />
|
||||
|
Loading…
Reference in New Issue
Block a user