mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Redesign player layout for tv (#479)
Co-authored-by: LagradOst <balt.758@gmail.com>
This commit is contained in:
parent
9f9251108a
commit
7185df6b68
11 changed files with 680 additions and 61 deletions
|
@ -37,7 +37,7 @@ object CommonActivity {
|
||||||
val onDialogDismissedEvent = Event<Int>()
|
val onDialogDismissedEvent = Event<Int>()
|
||||||
|
|
||||||
var playerEventListener: ((PlayerEventType) -> Unit)? = null
|
var playerEventListener: ((PlayerEventType) -> Unit)? = null
|
||||||
var keyEventListener: ((KeyEvent?) -> Boolean)? = null
|
var keyEventListener: ((Pair<KeyEvent?, Boolean>) -> Boolean)? = null
|
||||||
|
|
||||||
|
|
||||||
var currentToast: Toast? = null
|
var currentToast: Toast? = null
|
||||||
|
@ -134,8 +134,8 @@ object CommonActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadThemes(act: Activity? ) {
|
fun loadThemes(act: Activity?) {
|
||||||
if(act == null) return
|
if (act == null) return
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(act)
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(act)
|
||||||
|
|
||||||
val currentTheme =
|
val currentTheme =
|
||||||
|
@ -323,6 +323,7 @@ object CommonActivity {
|
||||||
val nextView = act.findViewById<View?>(next)
|
val nextView = act.findViewById<View?>(next)
|
||||||
if (nextView != null) {
|
if (nextView != null) {
|
||||||
nextView.requestFocus()
|
nextView.requestFocus()
|
||||||
|
keyEventListener?.invoke(Pair(event, true))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,7 +346,7 @@ object CommonActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyEventListener?.invoke(event) == true) {
|
if (keyEventListener?.invoke(Pair(event, false)) == true) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -58,7 +58,6 @@ const val PRELOAD_NEXT_EPISODE_PERCENTAGE = 80
|
||||||
const val NEXT_WATCH_EPISODE_PERCENTAGE = 95
|
const val NEXT_WATCH_EPISODE_PERCENTAGE = 95
|
||||||
|
|
||||||
abstract class AbstractPlayerFragment(
|
abstract class AbstractPlayerFragment(
|
||||||
@LayoutRes val layout: Int,
|
|
||||||
val player: IPlayer = CS3IPlayer()
|
val player: IPlayer = CS3IPlayer()
|
||||||
) : Fragment() {
|
) : Fragment() {
|
||||||
var resizeMode: Int = 0
|
var resizeMode: Int = 0
|
||||||
|
@ -66,6 +65,9 @@ abstract class AbstractPlayerFragment(
|
||||||
var subView: SubtitleView? = null
|
var subView: SubtitleView? = null
|
||||||
var isBuffering = true
|
var isBuffering = true
|
||||||
|
|
||||||
|
@LayoutRes
|
||||||
|
protected var layout: Int = R.layout.fragment_player
|
||||||
|
|
||||||
open fun nextEpisode() {
|
open fun nextEpisode() {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
@ -78,12 +80,12 @@ abstract class AbstractPlayerFragment(
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun playerDimensionsLoaded(widthHeight : Pair<Int, Int>) {
|
open fun playerDimensionsLoaded(widthHeight: Pair<Int, Int>) {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun keepScreenOn(on : Boolean) {
|
private fun keepScreenOn(on: Boolean) {
|
||||||
if(on) {
|
if (on) {
|
||||||
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
} else {
|
} else {
|
||||||
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
@ -128,7 +130,7 @@ abstract class AbstractPlayerFragment(
|
||||||
}
|
}
|
||||||
|
|
||||||
// somehow the phone is wacked
|
// somehow the phone is wacked
|
||||||
if(!startedAnimation) {
|
if (!startedAnimation) {
|
||||||
player_pause_play?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
player_pause_play?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -56,7 +56,7 @@ const val DOUBLE_TAB_MINIMUM_TIME_BETWEEN = 200L // this also affects the UI
|
||||||
const val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15 // in both directions
|
const val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15 // in both directions
|
||||||
|
|
||||||
// All the UI Logic for the player
|
// All the UI Logic for the player
|
||||||
open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
// state of player UI
|
// state of player UI
|
||||||
protected var isShowing = false
|
protected var isShowing = false
|
||||||
protected var isLocked = false
|
protected var isLocked = false
|
||||||
|
@ -352,6 +352,7 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
||||||
}
|
}
|
||||||
activity?.hideSystemUI()
|
activity?.hideSystemUI()
|
||||||
animateLayoutChanges()
|
animateLayoutChanges()
|
||||||
|
player_pause_play.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleLock() {
|
private fun toggleLock() {
|
||||||
|
@ -413,13 +414,15 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
||||||
|
|
||||||
private fun updateLockUI() {
|
private fun updateLockUI() {
|
||||||
player_lock?.setIconResource(if (isLocked) R.drawable.video_locked else R.drawable.video_unlocked)
|
player_lock?.setIconResource(if (isLocked) R.drawable.video_locked else R.drawable.video_unlocked)
|
||||||
val color = if (isLocked) context?.colorFromAttribute(R.attr.colorPrimary)
|
if (layout == R.layout.fragment_player) {
|
||||||
else Color.WHITE
|
val color = if (isLocked) context?.colorFromAttribute(R.attr.colorPrimary)
|
||||||
if (color != null) {
|
else Color.WHITE
|
||||||
player_lock?.setTextColor(color)
|
if (color != null) {
|
||||||
player_lock?.iconTint = ColorStateList.valueOf(color)
|
player_lock?.setTextColor(color)
|
||||||
player_lock?.rippleColor =
|
player_lock?.iconTint = ColorStateList.valueOf(color)
|
||||||
ColorStateList.valueOf(Color.argb(50, color.red, color.green, color.blue))
|
player_lock?.rippleColor =
|
||||||
|
ColorStateList.valueOf(Color.argb(50, color.red, color.green, color.blue))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,50 +822,71 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleKeyEvent(event: KeyEvent): Boolean {
|
private fun handleKeyEvent(event: KeyEvent, hasNavigated: Boolean): Boolean {
|
||||||
event.keyCode.let { keyCode ->
|
if (hasNavigated) {
|
||||||
when (event.action) {
|
autoHide()
|
||||||
KeyEvent.ACTION_DOWN -> {
|
} else {
|
||||||
when (keyCode) {
|
event.keyCode.let { keyCode ->
|
||||||
KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_DPAD_UP -> {
|
when (event.action) {
|
||||||
if (!isShowing) {
|
KeyEvent.ACTION_DOWN -> {
|
||||||
onClickChange()
|
when (keyCode) {
|
||||||
return true
|
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||||
|
if (!isShowing) {
|
||||||
|
if (!isLocked) player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
||||||
|
onClickChange()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||||
|
if (!isShowing) {
|
||||||
|
onClickChange()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||||
|
if (!isShowing && !isLocked) {
|
||||||
|
player.seekTime(-10000L)
|
||||||
|
return true
|
||||||
|
} else if (player_pause_play?.isFocused == true) {
|
||||||
|
player.seekTime(-30000L)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||||
|
if (!isShowing && !isLocked) {
|
||||||
|
player.seekTime(10000L)
|
||||||
|
return true
|
||||||
|
} else if (player_pause_play?.isFocused == true) {
|
||||||
|
player.seekTime(30000L)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//println("Keycode: $keyCode")
|
|
||||||
//showToast(
|
|
||||||
// this,
|
|
||||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
|
||||||
// Toast.LENGTH_LONG
|
|
||||||
//)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
when (keyCode) {
|
when (keyCode) {
|
||||||
// don't allow dpad move when hidden
|
// don't allow dpad move when hidden
|
||||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||||
KeyEvent.KEYCODE_DPAD_UP,
|
KeyEvent.KEYCODE_DPAD_UP,
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
KeyEvent.KEYCODE_DPAD_DOWN_LEFT,
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN_LEFT,
|
KeyEvent.KEYCODE_DPAD_DOWN_RIGHT,
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN_RIGHT,
|
KeyEvent.KEYCODE_DPAD_UP_LEFT,
|
||||||
KeyEvent.KEYCODE_DPAD_UP_LEFT,
|
KeyEvent.KEYCODE_DPAD_UP_RIGHT -> {
|
||||||
KeyEvent.KEYCODE_DPAD_UP_RIGHT -> {
|
if (!isShowing) {
|
||||||
if (!isShowing) {
|
return true
|
||||||
return true
|
} else {
|
||||||
} else {
|
autoHide()
|
||||||
autoHide()
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// netflix capture back and hide ~monke
|
// netflix capture back and hide ~monke
|
||||||
KeyEvent.KEYCODE_BACK -> {
|
KeyEvent.KEYCODE_BACK -> {
|
||||||
if (isShowing) {
|
if (isShowing) {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -940,12 +964,11 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle tv controls directly based on player state
|
// handle tv controls directly based on player state
|
||||||
keyEventListener = { keyEvent ->
|
keyEventListener = { eventNav ->
|
||||||
if (keyEvent != null) {
|
val (event, hasNavigated) = eventNav
|
||||||
handleKeyEvent(keyEvent)
|
if (event != null)
|
||||||
} else {
|
handleKeyEvent(event, hasNavigated)
|
||||||
false
|
else false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
|
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||||
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
@ -279,7 +280,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
sourceDialog.dismissSafe(activity)
|
sourceDialog.dismissSafe(activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,6 +486,10 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
|
// this is used instead of layout-television to follow the settings and some TV devices are not classified as TV for some reason
|
||||||
|
layout =
|
||||||
|
if (context?.isTvSettings() == true) R.layout.fragment_player_tv else R.layout.fragment_player
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]
|
viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]
|
||||||
viewModel.attachGenerator(lastUsedGenerator)
|
viewModel.attachGenerator(lastUsedGenerator)
|
||||||
return super.onCreateView(inflater, container, savedInstanceState)
|
return super.onCreateView(inflater, container, savedInstanceState)
|
||||||
|
|
5
app/src/main/res/color/player_button_tv.xml
Normal file
5
app/src/main/res/color/player_button_tv.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_focused="true" android:color="#FFFFFF"/>
|
||||||
|
<item android:color="#33FFFFFF"/>
|
||||||
|
</selector>
|
5
app/src/main/res/color/player_on_button_tv.xml
Normal file
5
app/src/main/res/color/player_on_button_tv.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_focused="true" android:color="@color/black"/>
|
||||||
|
<item android:color="@color/white"/>
|
||||||
|
</selector>
|
15
app/src/main/res/drawable/player_button_tv.xml
Normal file
15
app/src/main/res/drawable/player_button_tv.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_focused="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#33FFFFFF" />
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
26
app/src/main/res/drawable/player_gradient_tv.xml
Normal file
26
app/src/main/res/drawable/player_gradient_tv.xml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<gradient
|
||||||
|
android:angle="90"
|
||||||
|
android:startColor="#000000"
|
||||||
|
android:centerColor="#00000000"
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:centerY="0.7"
|
||||||
|
/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:startColor="#000000"
|
||||||
|
android:centerColor="#00000000"
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:centerY="0.7"
|
||||||
|
/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
138
app/src/main/res/layout/fragment_player_tv.xml
Normal file
138
app/src/main/res/layout/fragment_player_tv.xml
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:keepScreenOn="true"
|
||||||
|
android:id="@+id/player_background"
|
||||||
|
app:backgroundTint="@android:color/black"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
android:screenOrientation="sensorLandscape"
|
||||||
|
app:surface_type="texture_view"
|
||||||
|
>
|
||||||
|
<!--
|
||||||
|
app:fastforward_increment="10000"
|
||||||
|
app:rewind_increment="10000"-->
|
||||||
|
<com.google.android.exoplayer2.ui.PlayerView
|
||||||
|
android:id="@+id/player_view"
|
||||||
|
app:show_timeout="0"
|
||||||
|
app:hide_on_touch="false"
|
||||||
|
app:auto_show="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:controller_layout_id="@layout/player_custom_layout_tv"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/player_loading_overlay"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
android:backgroundTint="@android:color/black"
|
||||||
|
>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginTop="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:id="@+id/overlay_loading_skip_button"
|
||||||
|
android:text="@string/skip_loading"
|
||||||
|
|
||||||
|
app:rippleColor="?attr/colorPrimary"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
app:iconTint="?attr/textColor"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
app:icon="@drawable/ic_baseline_skip_next_24"
|
||||||
|
android:backgroundTint="@color/transparent"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="45dp">
|
||||||
|
</com.google.android.material.button.MaterialButton>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:id="@+id/main_load"
|
||||||
|
>
|
||||||
|
</ProgressBar>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/video_go_back_holder_holder"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
|
app:tint="@android:color/white"
|
||||||
|
>
|
||||||
|
</ImageView>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_loading_go_back"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/video_tap_button_always_white">
|
||||||
|
</ImageView>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:id="@+id/player_torrent_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
android:gravity="start"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:id="@+id/video_torrent_progress"
|
||||||
|
tools:text="78% at 18kb/s"
|
||||||
|
>
|
||||||
|
</TextView>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
android:gravity="start"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:id="@+id/video_torrent_seeders"
|
||||||
|
tools:text="17 seeders"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/player_video_title">
|
||||||
|
</TextView>
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
373
app/src/main/res/layout/player_custom_layout_tv.xml
Normal file
373
app/src/main/res/layout/player_custom_layout_tv.xml
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
<FrameLayout 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/player_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:screenOrientation="landscape"
|
||||||
|
tools:orientation="vertical"
|
||||||
|
android:tag="television">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/subtitle_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/shadow_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/player_gradient_tv" />
|
||||||
|
</FrameLayout>
|
||||||
|
<!--
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:id="@+id/video_lock_holder"
|
||||||
|
>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
android:id="@+id/video_locked_img"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:src="@drawable/video_locked">
|
||||||
|
</ImageView>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/video_lock"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/video_tap_button_always_white">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/player_video_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_top_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Hello world" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title_rez"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginTop="40dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="1920x1080" />
|
||||||
|
|
||||||
|
<!-- Removed as it has no use anymore-->
|
||||||
|
<!--<androidx.mediarouter.app.MediaRouteButton
|
||||||
|
android:id="@+id/player_media_route_button"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:mediaRouteTypes="user"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_go_back_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
|
app:tint="@android:color/white"
|
||||||
|
android:contentDescription="@string/go_back_img_des" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_go_back"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/video_tap_button_always_white"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/go_back_img_des"
|
||||||
|
android:focusable="true" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/player_buffering"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_prev"
|
||||||
|
style="@style/ExoMediaButton.Previous"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_repeat_toggle"
|
||||||
|
style="@style/ExoMediaButton"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_next"
|
||||||
|
style="@style/ExoMediaButton.Next"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_vr"
|
||||||
|
style="@style/ExoMediaButton.VR"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_play"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@id/exo_pause"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:tintMode="src_in"
|
||||||
|
app:tint="?attr/colorPrimaryDark"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bottom_player_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="64dp"
|
||||||
|
android:layout_marginEnd="64dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/player_video_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_pause_play"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:background="@drawable/video_tap_button"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:nextFocusUp="@id/player_go_back"
|
||||||
|
android:nextFocusDown="@id/player_lock"
|
||||||
|
|
||||||
|
android:src="@drawable/netflix_pause"
|
||||||
|
app:tint="@color/player_button_tv"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@id/exo_position"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="end"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:paddingLeft="4dp"
|
||||||
|
android:paddingRight="4dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="15:30" />
|
||||||
|
<!--app:buffered_color="@color/videoCache"-->
|
||||||
|
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
||||||
|
android:id="@id/exo_progress"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
app:bar_height="2dp"
|
||||||
|
app:played_color="?attr/colorPrimary"
|
||||||
|
app:scrubber_color="?attr/colorPrimary"
|
||||||
|
app:scrubber_dragged_size="26dp"
|
||||||
|
app:scrubber_enabled_size="24dp"
|
||||||
|
app:unplayed_color="@color/videoProgress" />
|
||||||
|
|
||||||
|
<!-- exo_duration-->
|
||||||
|
<TextView
|
||||||
|
android:id="@id/exo_duration"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:paddingLeft="4dp"
|
||||||
|
android:paddingRight="4dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="23:20" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_lock"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
android:nextFocusLeft="@id/player_skip_episode"
|
||||||
|
android:nextFocusRight="@id/player_resize_btt"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
android:text="@string/video_lock"
|
||||||
|
app:icon="@drawable/video_locked" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/player_lock_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_resize_btt"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
android:nextFocusLeft="@id/player_lock"
|
||||||
|
android:nextFocusRight="@id/player_speed_btt"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
android:text="@string/video_aspect_ratio_resize"
|
||||||
|
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_speed_btt"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
android:nextFocusLeft="@id/player_resize_btt"
|
||||||
|
android:nextFocusRight="@id/player_sources_btt"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
app:icon="@drawable/ic_baseline_speed_24"
|
||||||
|
tools:text="Speed" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_sources_btt"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
android:nextFocusLeft="@id/player_speed_btt"
|
||||||
|
android:nextFocusRight="@id/player_skip_op"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
android:text="@string/video_source"
|
||||||
|
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_op"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
android:nextFocusLeft="@id/player_sources_btt"
|
||||||
|
android:nextFocusRight="@id/player_skip_episode"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
android:text="@string/video_skip_op"
|
||||||
|
app:icon="@drawable/ic_baseline_fast_forward_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_episode"
|
||||||
|
style="@style/VideoButtonTV"
|
||||||
|
|
||||||
|
android:nextFocusLeft="@id/player_skip_op"
|
||||||
|
android:nextFocusRight="@id/player_lock"
|
||||||
|
android:nextFocusUp="@id/player_pause_play"
|
||||||
|
android:text="@string/next_episode"
|
||||||
|
app:icon="@drawable/ic_baseline_skip_next_24" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -421,6 +421,32 @@
|
||||||
<item name="android:layout_marginEnd">10dp</item>
|
<item name="android:layout_marginEnd">10dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="VideoButtonTV">
|
||||||
|
<item name="android:stateListAnimator">@null</item>
|
||||||
|
<item name="strokeColor">@color/transparent</item>
|
||||||
|
<item name="backgroundTint">@null</item>
|
||||||
|
<item name="android:background">@drawable/player_button_tv</item>
|
||||||
|
<item name="rippleColor">@color/white</item>
|
||||||
|
<item name="android:shadowColor">@color/transparent</item>
|
||||||
|
|
||||||
|
<item name="iconTint">@color/player_on_button_tv</item>
|
||||||
|
<item name="textColor">@color/player_on_button_tv</item>
|
||||||
|
<item name="android:textColor">@color/player_on_button_tv</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">25dp</item>
|
||||||
|
<item name="iconSize">16dp</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
|
<item name="android:baselineAligned">false</item>
|
||||||
|
<item name="textAllCaps">false</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:textSize">10sp</item>
|
||||||
|
<item name="android:layout_marginStart">4dp</item>
|
||||||
|
<item name="android:layout_marginEnd">4dp</item>
|
||||||
|
<item name="android:insetBottom">0dp</item>
|
||||||
|
<item name="android:insetTop">0dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<!--@color/white ?attr/colorPrimary-->
|
<!--@color/white ?attr/colorPrimary-->
|
||||||
<!--CHECK ?attr/darkBackground ?attr/colorPrimary-->
|
<!--CHECK ?attr/darkBackground ?attr/colorPrimary-->
|
||||||
<!-- CHROMECAST -->
|
<!-- CHROMECAST -->
|
||||||
|
|
Loading…
Reference in a new issue