Code refactor: Separate online and offline player

This commit is contained in:
Bnyro 2023-06-11 14:18:52 +02:00
parent 2a4aad88ee
commit 44d54d37c1
7 changed files with 229 additions and 194 deletions

View File

@ -5,13 +5,9 @@ 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.View
import android.view.ViewGroup.MarginLayoutParams
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
import androidx.core.view.marginTop
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.media3.common.C import androidx.media3.common.C
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
@ -30,9 +26,7 @@ import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.ActivityOfflinePlayerBinding import com.github.libretube.databinding.ActivityOfflinePlayerBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.DownloadItem
import com.github.libretube.enums.FileType import com.github.libretube.enums.FileType
import com.github.libretube.extensions.dpToPx
import com.github.libretube.extensions.toAndroidUri import com.github.libretube.extensions.toAndroidUri
import com.github.libretube.extensions.updateParameters import com.github.libretube.extensions.updateParameters
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
@ -105,24 +99,14 @@ class OfflinePlayerActivity : BaseActivity() {
playerView.player = player playerView.player = player
playerBinding = binding.player.binding playerBinding = binding.player.binding
// increase the margin to the status bar
playerBinding.topBar.setPadding(
playerBinding.topBar.paddingLeft,
playerBinding.topBar.paddingTop * 2,
playerBinding.topBar.paddingRight,
playerBinding.topBar.paddingBottom
)
playerBinding.fullscreen.isInvisible = true playerBinding.fullscreen.isInvisible = true
playerBinding.closeImageButton.setOnClickListener { playerBinding.closeImageButton.setOnClickListener {
finish() finish()
} }
binding.player.initialize( binding.player.initialize(
null,
binding.doubleTapOverlay.binding, binding.doubleTapOverlay.binding,
binding.playerGestureControlsView.binding, binding.playerGestureControlsView.binding,
trackSelector,
) )
} }
@ -181,6 +165,7 @@ class OfflinePlayerActivity : BaseActivity() {
player.setMediaSource(mediaSource) player.setMediaSource(mediaSource)
} }
videoUri != null -> player.setMediaItem( videoUri != null -> player.setMediaItem(
MediaItem.Builder() MediaItem.Builder()
.setUri(videoUri) .setUri(videoUri)
@ -189,6 +174,7 @@ class OfflinePlayerActivity : BaseActivity() {
} }
.build(), .build(),
) )
audioUri != null -> player.setMediaItem( audioUri != null -> player.setMediaItem(
MediaItem.Builder() MediaItem.Builder()
.setUri(audioUri) .setUri(audioUri)

View File

@ -16,7 +16,6 @@ import android.os.PowerManager
import android.text.format.DateUtils import android.text.format.DateUtils
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.text.util.Linkify import android.text.util.Linkify
import android.util.Base64
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -76,8 +75,6 @@ import com.github.libretube.extensions.toID
import com.github.libretube.extensions.toastFromMainDispatcher import com.github.libretube.extensions.toastFromMainDispatcher
import com.github.libretube.extensions.updateParameters import com.github.libretube.extensions.updateParameters
import com.github.libretube.helpers.BackgroundHelper import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.DashHelper
import com.github.libretube.helpers.DisplayHelper
import com.github.libretube.helpers.ImageHelper import com.github.libretube.helpers.ImageHelper
import com.github.libretube.helpers.LocaleHelper import com.github.libretube.helpers.LocaleHelper
import com.github.libretube.helpers.NavigationHelper import com.github.libretube.helpers.NavigationHelper
@ -892,14 +889,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun initializePlayerView() { private fun initializePlayerView() {
// initialize the player view actions // initialize the player view actions
binding.player.initialize( binding.player.initialize(doubleTapOverlayBinding, playerGestureControlsViewBinding)
this, binding.player.initPlayerOptions(viewModel, viewLifecycleOwner, trackSelector, this)
doubleTapOverlayBinding,
playerGestureControlsViewBinding,
trackSelector,
viewModel,
viewLifecycleOwner,
)
binding.apply { binding.apply {
val views = streams.views.formatShort() val views = streams.views.formatShort()

View File

@ -17,16 +17,13 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
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.lifecycle.LifecycleOwner
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.text.Cue import androidx.media3.common.text.Cue
import androidx.media3.common.util.RepeatModeUtil import androidx.media3.common.util.RepeatModeUtil
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.trackselection.TrackSelector
import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.CaptionStyleCompat import androidx.media3.ui.CaptionStyleCompat
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
@ -42,26 +39,23 @@ import com.github.libretube.extensions.round
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.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.WindowHelper
import com.github.libretube.obj.BottomSheetItem 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.interfaces.OnlinePlayerOptions
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
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.ui.sheets.BaseBottomSheet import com.github.libretube.ui.sheets.BaseBottomSheet
import com.github.libretube.ui.sheets.PlaybackOptionsSheet import com.github.libretube.ui.sheets.PlaybackOptionsSheet
import com.github.libretube.util.PlayingQueue import com.github.libretube.util.PlayingQueue
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
internal class CustomExoPlayerView( open class CustomExoPlayerView(
context: Context, context: Context,
attributeSet: AttributeSet? = null, attributeSet: AttributeSet? = null,
) : PlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions { ) : PlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions {
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this) @Suppress("LeakingThis")
val binding = ExoStyledPlayerControlViewBinding.bind(this)
/** /**
* Objects for player tap and swipe gesture * Objects for player tap and swipe gesture
@ -71,27 +65,20 @@ internal class CustomExoPlayerView(
private lateinit var brightnessHelper: BrightnessHelper private lateinit var brightnessHelper: BrightnessHelper
private lateinit var audioHelper: AudioHelper private lateinit var audioHelper: AudioHelper
private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null
private var playerViewModel: PlayerViewModel? = null
/** /**
* Objects from the parent fragment * Objects from the parent fragment
*/ */
private var playerOptionsInterface: OnlinePlayerOptions? = null
private var trackSelector: TrackSelector? = null
private val runnableHandler = Handler(Looper.getMainLooper()) private val runnableHandler = Handler(Looper.getMainLooper())
var isPlayerLocked: Boolean = false var isPlayerLocked: Boolean = false
/** /**
* Preferences * Preferences
*/ */
var autoplayEnabled = PlayerHelper.autoPlayEnabled
private var resizeModePref = PlayerHelper.resizeModePref private var resizeModePref = PlayerHelper.resizeModePref
private val activity val activity get() = context as BaseActivity
get() = context as BaseActivity
private val supportFragmentManager private val supportFragmentManager
get() = activity.supportFragmentManager get() = activity.supportFragmentManager
@ -101,18 +88,11 @@ internal class CustomExoPlayerView(
} }
fun initialize( fun initialize(
playerViewInterface: OnlinePlayerOptions?,
doubleTapOverlayBinding: DoubleTapOverlayBinding, doubleTapOverlayBinding: DoubleTapOverlayBinding,
playerGestureControlsViewBinding: PlayerGestureControlsViewBinding, playerGestureControlsViewBinding: PlayerGestureControlsViewBinding,
trackSelector: TrackSelector?,
playerViewModel: PlayerViewModel? = null,
viewLifecycleOwner: LifecycleOwner? = null,
) { ) {
this.playerOptionsInterface = playerViewInterface
this.doubleTapOverlayBinding = doubleTapOverlayBinding this.doubleTapOverlayBinding = doubleTapOverlayBinding
this.trackSelector = trackSelector
this.gestureViewBinding = playerGestureControlsViewBinding this.gestureViewBinding = playerGestureControlsViewBinding
this.playerViewModel = playerViewModel
this.playerGestureController = PlayerGestureController(context as BaseActivity, this) this.playerGestureController = PlayerGestureController(context as BaseActivity, this)
this.brightnessHelper = BrightnessHelper(context as Activity) this.brightnessHelper = BrightnessHelper(context as Activity)
this.audioHelper = AudioHelper(context) this.audioHelper = AudioHelper(context)
@ -123,7 +103,7 @@ internal class CustomExoPlayerView(
initRewindAndForward() initRewindAndForward()
applyCaptionsStyle() applyCaptionsStyle()
initializeAdvancedOptions(context) initializeAdvancedOptions()
// don't let the player view hide its controls automatically // don't let the player view hide its controls automatically
controllerShowTimeoutMs = -1 controllerShowTimeoutMs = -1
@ -148,12 +128,6 @@ internal class CustomExoPlayerView(
isPlayerLocked = !isPlayerLocked isPlayerLocked = !isPlayerLocked
} }
binding.autoPlay.isChecked = autoplayEnabled
binding.autoPlay.setOnCheckedChangeListener { _, isChecked ->
autoplayEnabled = isChecked
}
resizeMode = when (resizeModePref) { resizeMode = when (resizeModePref) {
"fill" -> AspectRatioFrameLayout.RESIZE_MODE_FILL "fill" -> AspectRatioFrameLayout.RESIZE_MODE_FILL
"zoom" -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM "zoom" -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
@ -183,11 +157,7 @@ internal class CustomExoPlayerView(
// keep screen on if the video is playing // keep screen on if the video is playing
keepScreenOn = player.isPlaying == true keepScreenOn = player.isPlaying == true
onPlayerEvent(player, events)
if (player.playbackState == Player.STATE_ENDED && !autoplayEnabled) {
showController()
cancelHideControllerTask()
}
} }
} }
}) })
@ -206,26 +176,10 @@ internal class CustomExoPlayerView(
enqueueHideControllerTask() enqueueHideControllerTask()
} }
}) })
setControllerVisibilityListener(
ControllerVisibilityListener { visibility ->
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(
types = WindowInsetsCompat.Type.statusBars(),
showBars = visibility == View.VISIBLE,
)
}
},
)
playerViewModel?.isFullscreen?.observe(viewLifecycleOwner!!) { isFullscreen ->
WindowHelper.toggleFullscreen(activity, isFullscreen)
updateTopBarMargin()
}
} }
open fun onPlayerEvent(player: Player, playerEvents: Player.Events) = Unit
private fun updatePlayPauseButton() { private fun updatePlayPauseButton() {
binding.playPauseBTN.setImageResource( binding.playPauseBTN.setImageResource(
when { when {
@ -250,16 +204,6 @@ internal class CustomExoPlayerView(
// remove the callback to hide the controller // remove the callback to hide the controller
cancelHideControllerTask() cancelHideControllerTask()
super.hideController() super.hideController()
// hide system bars if in fullscreen or offline player
if (playerViewModel != null) {
if (playerViewModel!!.isFullscreen.value == true) {
WindowHelper.toggleFullscreen(activity, true)
}
updateTopBarMargin()
} else {
activity.toggleSystemBars(WindowInsetsCompat.Type.systemBars(), false)
}
} }
override fun showController() { override fun showController() {
@ -268,11 +212,6 @@ internal class CustomExoPlayerView(
// automatically hide the controller after 2 seconds // automatically hide the controller after 2 seconds
enqueueHideControllerTask() enqueueHideControllerTask()
super.showController() super.showController()
// show the system bars when in offline player
if (playerViewModel == null) {
activity.toggleSystemBars(WindowInsetsCompat.Type.statusBars(), true)
}
} }
override fun onTouchEvent(event: MotionEvent) = false override fun onTouchEvent(event: MotionEvent) = false
@ -300,97 +239,56 @@ internal class CustomExoPlayerView(
} }
} }
private fun initializeAdvancedOptions(context: Context) { private fun initializeAdvancedOptions() {
binding.toggleOptions.setOnClickListener { binding.toggleOptions.setOnClickListener {
val items = mutableListOf( val items = getOptionsMenuItems()
BottomSheetItem(
context.getString(R.string.repeat_mode),
R.drawable.ic_repeat,
{
if (player?.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) {
context.getString(R.string.repeat_mode_none)
} else {
context.getString(R.string.repeat_mode_current)
}
},
) {
onRepeatModeClicked()
},
BottomSheetItem(
context.getString(R.string.player_resize_mode),
R.drawable.ic_aspect_ratio,
{
when (resizeMode) {
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(
R.string.resize_mode_fit,
)
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(
R.string.resize_mode_fill,
)
else -> context.getString(R.string.resize_mode_zoom)
}
},
) {
onResizeModeClicked()
},
BottomSheetItem(
context.getString(R.string.playback_speed),
R.drawable.ic_speed,
{
"${player?.playbackParameters?.speed?.round(2)}x"
},
) {
onPlaybackSpeedClicked()
},
)
playerOptionsInterface?.let {
items.addAll(
listOf(
BottomSheetItem(
context.getString(R.string.quality),
R.drawable.ic_hd,
{ "${player?.videoSize?.height}p" },
) {
it.onQualityClicked()
},
BottomSheetItem(
context.getString(R.string.audio_track),
R.drawable.ic_audio,
{
trackSelector?.parameters?.preferredAudioLanguages?.firstOrNull()
},
) {
it.onAudioStreamClicked()
},
BottomSheetItem(
context.getString(R.string.captions),
R.drawable.ic_caption,
{
if (trackSelector != null && trackSelector!!.parameters.preferredTextLanguages.isNotEmpty()) {
trackSelector!!.parameters.preferredTextLanguages[0]
} else {
context.getString(R.string.none)
}
},
) {
it.onCaptionsClicked()
},
BottomSheetItem(
context.getString(R.string.stats_for_nerds),
R.drawable.ic_info,
) {
it.onStatsClicked()
},
),
)
}
val bottomSheetFragment = BaseBottomSheet().setItems(items, null) val bottomSheetFragment = BaseBottomSheet().setItems(items, null)
bottomSheetFragment.show(supportFragmentManager, null) bottomSheetFragment.show(supportFragmentManager, null)
} }
} }
open fun getOptionsMenuItems(): List<BottomSheetItem> = listOf(
BottomSheetItem(
context.getString(R.string.repeat_mode),
R.drawable.ic_repeat,
{
if (player?.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) {
context.getString(R.string.repeat_mode_none)
} else {
context.getString(R.string.repeat_mode_current)
}
},
) {
onRepeatModeClicked()
},
BottomSheetItem(
context.getString(R.string.player_resize_mode),
R.drawable.ic_aspect_ratio,
{
when (resizeMode) {
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(
R.string.resize_mode_fit,
)
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(
R.string.resize_mode_fill,
)
else -> context.getString(R.string.resize_mode_zoom)
}
},
) {
onResizeModeClicked()
},
BottomSheetItem(
context.getString(R.string.playback_speed),
R.drawable.ic_speed,
{
"${player?.playbackParameters?.speed?.round(2)}x"
},
) {
onPlaybackSpeedClicked()
},
)
// lock the player // lock the player
private fun lockPlayer(isLocked: Boolean) { private fun lockPlayer(isLocked: Boolean) {
// isLocked is the current (old) state of the player lock // isLocked is the current (old) state of the player lock
@ -606,12 +504,14 @@ internal class CustomExoPlayerView(
.show(supportFragmentManager) .show(supportFragmentManager)
} }
open fun isFullscreen() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
// add a larger bottom margin to the time bar in landscape mode // add a larger bottom margin to the time bar in landscape mode
val offset = when { val offset = when {
playerViewModel?.isFullscreen?.value ?: (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) -> 20.dpToPx() isFullscreen() -> 20.dpToPx()
else -> 10.dpToPx() else -> 10.dpToPx()
} }
@ -656,17 +556,16 @@ internal class CustomExoPlayerView(
/** /**
* Add extra margin to the top bar to not overlap the status bar * Add extra margin to the top bar to not overlap the status bar
*/ */
private fun updateTopBarMargin() { fun updateTopBarMargin() {
val margin = when {
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE -> 10
playerViewModel?.isFullscreen?.value == true -> 20
else -> 0
}
binding.topBar.updateLayoutParams<MarginLayoutParams> { binding.topBar.updateLayoutParams<MarginLayoutParams> {
topMargin = margin.dpToPx().toInt() topMargin = getTopBarMarginDp().dpToPx().toInt()
} }
} }
open fun getTopBarMarginDp(): Int {
return if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 10 else 0
}
override fun onSingleTap() { override fun onSingleTap() {
toggleController() toggleController()
} }
@ -719,7 +618,6 @@ internal class CustomExoPlayerView(
playerGestureController.isMoving = false playerGestureController.isMoving = false
(context as? AppCompatActivity)?.onBackPressedDispatcher?.onBackPressed() (context as? AppCompatActivity)?.onBackPressedDispatcher?.onBackPressed()
playerViewModel?.isFullscreen?.value = false
} }
override fun onSwipeEnd() { override fun onSwipeEnd() {

View File

@ -0,0 +1,28 @@
package com.github.libretube.ui.views
import android.content.Context
import android.util.AttributeSet
import androidx.core.view.WindowInsetsCompat
import com.github.libretube.ui.extensions.toggleSystemBars
class OfflinePlayerView(
context: Context,
attributeSet: AttributeSet? = null,
): CustomExoPlayerView(context, attributeSet) {
override fun hideController() {
super.hideController()
// hide the status bars when continuing to watch video
activity.toggleSystemBars(WindowInsetsCompat.Type.systemBars(), false)
}
override fun showController() {
super.showController()
// show status bar when showing player options
activity.toggleSystemBars(WindowInsetsCompat.Type.statusBars(), true)
}
override fun getTopBarMarginDp(): Int {
// the offline player requires a bigger top bar margin
return if (isFullscreen()) 18 else super.getTopBarMarginDp()
}
}

View File

@ -0,0 +1,132 @@
package com.github.libretube.ui.views
import android.content.Context
import android.content.res.Configuration
import android.util.AttributeSet
import android.view.View
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.LifecycleOwner
import androidx.media3.exoplayer.trackselection.TrackSelector
import com.github.libretube.R
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.WindowHelper
import com.github.libretube.obj.BottomSheetItem
import com.github.libretube.ui.extensions.toggleSystemBars
import com.github.libretube.ui.interfaces.OnlinePlayerOptions
import com.github.libretube.ui.models.PlayerViewModel
class OnlinePlayerView(
context: Context,
attributeSet: AttributeSet? = null,
) : CustomExoPlayerView(context, attributeSet) {
private var playerOptions: OnlinePlayerOptions? = null
private var playerViewModel: PlayerViewModel? = null
private var trackSelector: TrackSelector? = null
private var viewLifecycleOwner: LifecycleOwner? = null
var autoplayEnabled = PlayerHelper.autoPlayEnabled
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
override fun getOptionsMenuItems(): List<BottomSheetItem> {
return super.getOptionsMenuItems() +
listOf(
BottomSheetItem(
context.getString(R.string.quality),
R.drawable.ic_hd,
{ "${player?.videoSize?.height}p" },
) {
playerOptions?.onQualityClicked()
},
BottomSheetItem(
context.getString(R.string.audio_track),
R.drawable.ic_audio,
{
trackSelector?.parameters?.preferredAudioLanguages?.firstOrNull()
},
) {
playerOptions?.onAudioStreamClicked()
},
BottomSheetItem(
context.getString(R.string.captions),
R.drawable.ic_caption,
{
if (trackSelector != null && trackSelector!!.parameters.preferredTextLanguages.isNotEmpty()) {
trackSelector!!.parameters.preferredTextLanguages[0]
} else {
context.getString(R.string.none)
}
},
) {
playerOptions?.onCaptionsClicked()
},
BottomSheetItem(
context.getString(R.string.stats_for_nerds),
R.drawable.ic_info,
) {
playerOptions?.onStatsClicked()
},
)
}
fun initPlayerOptions(
playerViewModel: PlayerViewModel,
viewLifecycleOwner: LifecycleOwner,
trackSelector: TrackSelector,
playerOptions: OnlinePlayerOptions
) {
this.playerViewModel = playerViewModel
this.viewLifecycleOwner = viewLifecycleOwner
this.trackSelector = trackSelector
this.playerOptions = playerOptions
playerViewModel.isFullscreen.observe(viewLifecycleOwner) { isFullscreen ->
WindowHelper.toggleFullscreen(activity, isFullscreen)
updateTopBarMargin()
}
setControllerVisibilityListener(
ControllerVisibilityListener { visibility ->
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(
types = WindowInsetsCompat.Type.statusBars(),
showBars = visibility == View.VISIBLE,
)
}
},
)
binding.autoPlay.isChecked = autoplayEnabled
binding.autoPlay.setOnCheckedChangeListener { _, isChecked ->
autoplayEnabled = isChecked
}
}
override fun hideController() {
super.hideController()
if (playerViewModel?.isFullscreen?.value == true) {
WindowHelper.toggleFullscreen(activity, true)
}
updateTopBarMargin()
}
override fun onSwipeCenterScreen(distanceY: Float) {
super.onSwipeCenterScreen(distanceY)
playerViewModel?.isFullscreen?.value = false
}
override fun getTopBarMarginDp(): Int {
return when {
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE -> 15
playerViewModel?.isFullscreen?.value == true -> 20
else -> super.getTopBarMarginDp()
}
}
override fun isFullscreen(): Boolean {
return playerViewModel?.isFullscreen?.value ?: super.isFullscreen()
}
}

View File

@ -5,7 +5,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.github.libretube.ui.views.CustomExoPlayerView <com.github.libretube.ui.views.OfflinePlayerView
android:id="@+id/player" android:id="@+id/player"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -27,6 +27,6 @@
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" /> android:gravity="center" />
</com.github.libretube.ui.views.CustomExoPlayerView> </com.github.libretube.ui.views.OfflinePlayerView>
</LinearLayout> </LinearLayout>

View File

@ -299,7 +299,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.github.libretube.ui.views.CustomExoPlayerView <com.github.libretube.ui.views.OnlinePlayerView
android:id="@+id/player" android:id="@+id/player"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -357,7 +357,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" /> android:visibility="gone" />
</com.github.libretube.ui.views.CustomExoPlayerView> </com.github.libretube.ui.views.OnlinePlayerView>
<ImageView <ImageView
android:id="@+id/close_imageView" android:id="@+id/close_imageView"