Add audio and video track support (#69)

* Add audio and video track support
This commit is contained in:
LagradOst 2022-08-31 21:58:26 +02:00 committed by GitHub
parent 7a68d6304f
commit 461f3d75d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1283 additions and 809 deletions

View File

@ -99,6 +99,10 @@ abstract class AbstractPlayerFragment(
throw NotImplementedError()
}
open fun onTracksInfoChanged() {
throw NotImplementedError()
}
open fun exitedPipMode() {
throw NotImplementedError()
}
@ -369,6 +373,7 @@ abstract class AbstractPlayerFragment(
),
subtitlesUpdates = ::subtitlesChanged,
embeddedSubtitlesFetched = ::embeddedSubtitlesFetched,
onTracksInfoChanged = ::onTracksInfoChanged
)
if (player is CS3IPlayer) {

View File

@ -8,6 +8,8 @@ import android.util.Log
import android.widget.FrameLayout
import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.C.TRACK_TYPE_AUDIO
import com.google.android.exoplayer2.C.TRACK_TYPE_VIDEO
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
import com.google.android.exoplayer2.source.*
@ -24,6 +26,8 @@ import com.google.android.exoplayer2.upstream.cache.SimpleCache
import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.exoplayer2.video.VideoSize
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError
@ -39,6 +43,7 @@ import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession
const val TAG = "CS3ExoPlayer"
const val PREFERRED_AUDIO_LANGUAGE_KEY = "preferred_audio_language"
/** Cache */
@ -108,6 +113,7 @@ class CS3IPlayer : IPlayer {
private var playerUpdated: ((Any?) -> Unit)? = null
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
private var onTracksInfoChanged: (() -> Unit)? = null
override fun releaseCallbacks() {
playerUpdated = null
@ -120,7 +126,7 @@ class CS3IPlayer : IPlayer {
nextEpisode = null
prevEpisode = null
subtitlesUpdates = null
embeddedSubtitlesFetched = null
onTracksInfoChanged = null
requestSubtitleUpdate = null
}
@ -136,6 +142,7 @@ class CS3IPlayer : IPlayer {
prevEpisode: (() -> Unit)?,
subtitlesUpdates: (() -> Unit)?,
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)?,
onTracksInfoChanged: (() -> Unit)?,
) {
this.playerUpdated = playerUpdated
this.updateIsPlaying = updateIsPlaying
@ -148,6 +155,7 @@ class CS3IPlayer : IPlayer {
this.prevEpisode = prevEpisode
this.subtitlesUpdates = subtitlesUpdates
this.embeddedSubtitlesFetched = embeddedSubtitlesFetched
this.onTracksInfoChanged = onTracksInfoChanged
}
// I know, this is not a perfect solution, however it works for fixing subs
@ -212,6 +220,72 @@ class CS3IPlayer : IPlayer {
var currentSubtitles: SubtitleData? = null
override fun setMaxVideoSize(width: Int, height: Int) {
exoPlayer?.trackSelectionParameters = exoPlayer?.trackSelectionParameters
?.buildUpon()
?.setMaxVideoSize(width, height)
?.build()
?: return
}
override fun setPreferredAudioTrack(trackLanguage: String?) {
preferredAudioTrackLanguage = trackLanguage
exoPlayer?.trackSelectionParameters = exoPlayer?.trackSelectionParameters
?.buildUpon()
?.setPreferredAudioLanguage(trackLanguage)
?.build()
?: return
}
/**
* Gets all supported formats in a list
* */
private fun List<TracksInfo.TrackGroupInfo>.getFormats(): List<Format> {
return this.map {
(0 until it.trackGroup.length).mapNotNull { i ->
if (it.isSupported)
it.trackGroup.getFormat(i) // to it.isSelected
else null
}
}.flatten()
}
private fun Format.toAudioTrack(): AudioTrack {
return AudioTrack(
this.id,
this.label,
// isPlaying,
this.language
)
}
private fun Format.toVideoTrack(): VideoTrack {
return VideoTrack(
this.id,
this.label,
// isPlaying,
this.language,
this.width,
this.height
)
}
override fun getVideoTracks(): CurrentTracks {
val allTracks = exoPlayer?.currentTracksInfo?.trackGroupInfos ?: emptyList()
val videoTracks = allTracks.filter { it.trackType == TRACK_TYPE_VIDEO }.getFormats()
.map { it.toVideoTrack() }
val audioTracks = allTracks.filter { it.trackType == TRACK_TYPE_AUDIO }.getFormats()
.map { it.toAudioTrack() }
return CurrentTracks(
exoPlayer?.videoFormat?.toVideoTrack(),
exoPlayer?.audioFormat?.toAudioTrack(),
videoTracks,
audioTracks
)
}
/**
* @return True if the player should be reloaded
* */
@ -350,6 +424,20 @@ class CS3IPlayer : IPlayer {
}
companion object {
/**
* Setting this variable is permanent across app sessions.
**/
private var preferredAudioTrackLanguage: String? = null
get() {
return field ?: getKey(PREFERRED_AUDIO_LANGUAGE_KEY, field)?.also {
field = it
}
}
set(value) {
setKey(PREFERRED_AUDIO_LANGUAGE_KEY, value)
field = value
}
private var simpleCache: SimpleCache? = null
var requestSubtitleUpdate: (() -> Unit)? = null
@ -460,13 +548,21 @@ class CS3IPlayer : IPlayer {
return getMediaItemBuilder(mimeType).setUri(url).build()
}
private fun getTrackSelector(context: Context): TrackSelector {
private fun getTrackSelector(context: Context, maxVideoHeight: Int?): TrackSelector {
val trackSelector = DefaultTrackSelector(context)
trackSelector.parameters = DefaultTrackSelector.ParametersBuilder(context)
// .setRendererDisabled(C.TRACK_TYPE_VIDEO, true)
.setRendererDisabled(C.TRACK_TYPE_TEXT, true)
// Experimental
.setTunnelingEnabled(true)
.setDisabledTextTrackSelectionFlags(C.TRACK_TYPE_TEXT)
.clearSelectionOverrides()
// This will not force higher quality videos to fail
// but will make the m3u8 pick the correct preferred
.setMaxVideoSize(Int.MAX_VALUE, maxVideoHeight ?: Int.MAX_VALUE)
.setPreferredAudioLanguage(preferredAudioTrackLanguage)
// This would also clear preferred audio
// .clearSelectionOverrides()
.build()
return trackSelector
}
@ -486,6 +582,11 @@ class CS3IPlayer : IPlayer {
playWhenReady: Boolean = true,
cacheFactory: CacheDataSource.Factory? = null,
trackSelector: TrackSelector? = null,
/**
* Sets the m3u8 preferred video quality, will not force stop anything with higher quality.
* Does not work if trackSelector is defined.
**/
maxVideoHeight: Int? = null
): ExoPlayer {
val exoPlayerBuilder =
ExoPlayer.Builder(context)
@ -508,7 +609,7 @@ class CS3IPlayer : IPlayer {
} else it
}.toTypedArray()
}
.setTrackSelector(trackSelector ?: getTrackSelector(context))
.setTrackSelector(trackSelector ?: getTrackSelector(context, maxVideoHeight))
.setLoadControl(
DefaultLoadControl.Builder()
.setTargetBufferBytes(
@ -637,6 +738,12 @@ class CS3IPlayer : IPlayer {
cacheFactory: CacheDataSource.Factory? = null
) {
Log.i(TAG, "loadExo")
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
val maxVideoHeight = settingsManager.getInt(
context.getString(com.lagradost.cloudstream3.R.string.quality_pref_key),
Int.MAX_VALUE
)
try {
hasUsedFirstRender = false
@ -653,7 +760,8 @@ class CS3IPlayer : IPlayer {
videoBufferMs = videoBufferMs,
playWhenReady = isPlaying, // this keep the current state of the player
cacheFactory = cacheFactory,
subtitleOffset = currentSubtitleOffset
subtitleOffset = currentSubtitleOffset,
maxVideoHeight = maxVideoHeight
)
requestSubtitleUpdate = ::reloadSubs
@ -713,6 +821,7 @@ class CS3IPlayer : IPlayer {
}
embeddedSubtitlesFetched?.invoke(exoPlayerReportedTracks)
onTracksInfoChanged?.invoke()
subtitlesUpdates?.invoke()
}
super.onTracksInfoChanged(tracksInfo)

View File

@ -176,6 +176,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
throw NotImplementedError()
}
open fun showTracksDialogue() {
throw NotImplementedError()
}
open fun openOnlineSubPicker(
context: Context,
imdbId: Long?,
@ -1101,6 +1105,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
// if nothing has loaded these buttons should not be visible
player_skip_episode?.isVisible = false
player_tracks_btt?.isVisible = false
player_skip_op?.isVisible = false
shadow_overlay?.isVisible = false
@ -1296,6 +1301,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
showMirrorsDialogue()
}
player_tracks_btt?.setOnClickListener {
showTracksDialogue()
}
player_intro_play?.setOnClickListener {
player_intro_play?.isGone = true
player.handleEvent(CSPlayerEvent.Play)

View File

@ -18,6 +18,11 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.C.TRACK_TYPE_AUDIO
import com.google.android.exoplayer2.C.TRACK_TYPE_VIDEO
import com.google.android.exoplayer2.Format
import com.google.android.exoplayer2.Format.NO_VALUE
import com.google.android.exoplayer2.TracksInfo
import com.google.android.exoplayer2.util.MimeTypes
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.*
@ -53,6 +58,8 @@ import kotlinx.android.synthetic.main.dialog_online_subtitles.cancel_btt
import kotlinx.android.synthetic.main.fragment_player.*
import kotlinx.android.synthetic.main.player_custom_layout.*
import kotlinx.android.synthetic.main.player_select_source_and_subs.*
import kotlinx.android.synthetic.main.player_select_source_and_subs.subtitles_click_settings
import kotlinx.android.synthetic.main.player_select_tracks.*
import kotlinx.coroutines.Job
class GeneratorPlayer : FullScreenPlayer() {
@ -109,6 +116,11 @@ class GeneratorPlayer : FullScreenPlayer() {
viewModel.addSubtitles(subtitles.toSet())
}
override fun onTracksInfoChanged() {
val tracks = player.getVideoTracks()
player_tracks_btt?.isVisible = tracks.allVideoTracks.size > 1 || tracks.allAudioTracks.size > 1
}
private fun noSubtitles(): Boolean {
return setSubtitles(null)
}
@ -477,6 +489,8 @@ class GeneratorPlayer : FullScreenPlayer() {
}
var selectSourceDialog: AlertDialog? = null
// var selectTracksDialog: AlertDialog? = null
override fun showMirrorsDialogue() {
try {
currentSelectedSubtitles = player.getCurrentPreferredSubtitle()
@ -668,6 +682,121 @@ class GeneratorPlayer : FullScreenPlayer() {
}
}
override fun showTracksDialogue() {
try {
//println("CURRENT SELECTED :$currentSelectedSubtitles of $currentSubs")
context?.let { ctx ->
val tracks = player.getVideoTracks()
val isPlaying = player.getIsPlaying()
player.handleEvent(CSPlayerEvent.Pause)
val currentVideoTracks = tracks.allVideoTracks.sortedBy {
it.height?.times(-1)
}
val currentAudioTracks = tracks.allAudioTracks
val trackBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack)
.setView(R.layout.player_select_tracks)
val tracksDialog = trackBuilder.create()
// selectTracksDialog = tracksDialog
tracksDialog.show()
val videosList = tracksDialog.video_tracks_list
val audioList = tracksDialog.auto_tracks_list
tracksDialog.video_tracks_holder.isVisible = currentVideoTracks.size > 1
tracksDialog.audio_tracks_holder.isVisible = currentAudioTracks.size > 1
fun dismiss() {
if (isPlaying) {
player.handleEvent(CSPlayerEvent.Play)
}
activity?.hideSystemUI()
}
val videosArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
videosArrayAdapter.addAll(currentVideoTracks.mapIndexed { index, format ->
format.label
?: (if (format.height == NO_VALUE || format.width == NO_VALUE) index else "${format.width}x${format.height}").toString()
})
videosList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
videosList.adapter = videosArrayAdapter
// Sometimes the data is not the same because some data gets resolved at different stages i think
var videoIndex = currentVideoTracks.indexOf(tracks.currentVideoTrack).takeIf {
it != -1
} ?: currentVideoTracks.indexOfFirst {
tracks.currentVideoTrack?.id == it.id
}
videosList.setSelection(videoIndex)
videosList.setItemChecked(videoIndex, true)
videosList.setOnItemClickListener { _, _, which, _ ->
videoIndex = which
videosList.setItemChecked(which, true)
}
tracksDialog.setOnDismissListener {
dismiss()
// selectTracksDialog = null
}
var audioIndexStart = currentAudioTracks.indexOf(tracks.currentAudioTrack).takeIf {
it != -1
} ?: currentVideoTracks.indexOfFirst {
tracks.currentAudioTrack?.id == it.id
}
val audioArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
// audioArrayAdapter.add(ctx.getString(R.string.no_subtitles))
audioArrayAdapter.addAll(currentAudioTracks.mapIndexed { index, format ->
format.label ?: format.language?.let { fromTwoLettersToLanguage(it) } ?: index.toString()
})
audioList.adapter = audioArrayAdapter
audioList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
audioList.setSelection(audioIndexStart)
audioList.setItemChecked(audioIndexStart, true)
audioList.setOnItemClickListener { _, _, which, _ ->
audioIndexStart = which
audioList.setItemChecked(which, true)
}
tracksDialog.cancel_btt?.setOnClickListener {
tracksDialog.dismissSafe(activity)
}
tracksDialog.apply_btt?.setOnClickListener {
player.setPreferredAudioTrack(
currentAudioTracks.getOrNull(audioIndexStart)?.language
)
val currentVideo = currentVideoTracks.getOrNull(videoIndex)
val width = currentVideo?.width ?: NO_VALUE
val height = currentVideo?.height ?: NO_VALUE
if (width != NO_VALUE && height != NO_VALUE) {
player.setMaxVideoSize(width, height)
}
tracksDialog.dismissSafe(activity)
}
}
} catch (e: Exception) {
logError(e)
}
}
override fun playerError(exception: Exception) {
Log.i(TAG, "playerError = $currentSelectedLink")
super.playerError(exception)

View File

@ -46,7 +46,42 @@ enum class CSPlayerLoading {
//IsDone,
}
class InvalidFileException(msg : String) : Exception(msg)
interface Track {
/**
* Unique among the class, used to check which track is used.
* VideoTrack and AudioTrack can have the same id
**/
val id: String?
val label: String?
// val isCurrentlyPlaying: Boolean
val language: String?
}
data class VideoTrack(
override val id: String?,
override val label: String?,
// override val isCurrentlyPlaying: Boolean,
override val language: String?,
val width: Int?,
val height: Int?,
) : Track
data class AudioTrack(
override val id: String?,
override val label: String?,
// override val isCurrentlyPlaying: Boolean,
override val language: String?,
) : Track
data class CurrentTracks(
val currentVideoTrack: VideoTrack?,
val currentAudioTrack: AudioTrack?,
val allVideoTracks: List<VideoTrack>,
val allAudioTracks: List<AudioTrack>,
)
class InvalidFileException(msg: String) : Exception(msg)
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
const val STATE_RESUME_WINDOW = "resumeWindow"
@ -73,8 +108,8 @@ interface IPlayer {
fun seekTime(time: Long)
fun seekTo(time: Long)
fun getSubtitleOffset() : Long // in ms
fun setSubtitleOffset(offset : Long) // in ms
fun getSubtitleOffset(): Long // in ms
fun setSubtitleOffset(offset: Long) // in ms
fun initCallbacks(
playerUpdated: (Any?) -> Unit, // attach player to view
@ -88,7 +123,9 @@ interface IPlayer {
prevEpisode: (() -> Unit)? = null, // this is used by the player to load the previous episode
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
onTracksInfoChanged: (() -> Unit)? = null, // Callback when tracks are changed, used for UI changes
)
fun releaseCallbacks()
fun updateSubtitleStyle(style: SaveCaptionStyle)
@ -100,16 +137,16 @@ interface IPlayer {
link: ExtractorLink? = null,
data: ExtractorUri? = null,
startPosition: Long? = null,
subtitles : Set<SubtitleData>,
subtitle : SubtitleData?,
autoPlay : Boolean? = true
subtitles: Set<SubtitleData>,
subtitle: SubtitleData?,
autoPlay: Boolean? = true
)
fun reloadPlayer(context: Context)
fun setActiveSubtitles(subtitles : Set<SubtitleData>)
fun setPreferredSubtitles(subtitle : SubtitleData?) : Boolean // returns true if the player requires a reload, null for nothing
fun getCurrentPreferredSubtitle() : SubtitleData?
fun setActiveSubtitles(subtitles: Set<SubtitleData>)
fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean // returns true if the player requires a reload, null for nothing
fun getCurrentPreferredSubtitle(): SubtitleData?
fun handleEvent(event: CSPlayerEvent)
@ -120,5 +157,13 @@ interface IPlayer {
fun release()
/** Get if player is actually used */
fun isActive() : Boolean
fun isActive(): Boolean
fun getVideoTracks(): CurrentTracks
/** If no parameters are set it'll default to no set size */
fun setMaxVideoSize(width: Int = Int.MAX_VALUE, height: Int = Int.MAX_VALUE)
/** If no trackLanguage is set it'll default to first track */
fun setPreferredAudioTrack(trackLanguage: String?)
}

View File

@ -75,11 +75,14 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
}
override fun showMirrorsDialogue() {}
override fun showTracksDialogue() {}
override fun openOnlineSubPicker(context: Context, imdbId: Long?, dismissCallback: () -> Unit) {}
override fun subtitlesChanged() {}
override fun embeddedSubtitlesFetched(subtitles: List<SubtitleData>) {}
override fun onTracksInfoChanged() {}
override fun exitedPipMode() {}

View File

@ -116,15 +116,16 @@ class M3u8Helper {
return !url.contains("https://") && !url.contains("http://")
}
suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean?): List<M3u8Stream> {
suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean? = true): List<M3u8Stream> {
// return listOf(m3u8)
val list = mutableListOf<M3u8Stream>()
val m3u8Parent = getParentLink(m3u8.streamUrl)
val response = app.get(m3u8.streamUrl, headers = m3u8.headers, verify = false).text
var hasAnyContent = false
// var hasAnyContent = false
for (match in QUALITY_REGEX.findAll(response)) {
hasAnyContent = true
// hasAnyContent = true
var (quality, m3u8Link, m3u8Link2) = match.destructured
if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2
if (absoluteExtensionDetermination(m3u8Link) == "m3u8") {
@ -141,16 +142,14 @@ class M3u8Helper {
m3u8.headers
), false
)
}
list += M3u8Stream(
m3u8Link,
quality.toIntOrNull(),
m3u8.headers
)
}
if (returnThis ?: !hasAnyContent) {
if (returnThis != false) {
list += M3u8Stream(
m3u8.streamUrl,
Qualities.Unknown.value,
@ -169,7 +168,10 @@ class M3u8Helper {
val errored: Boolean = false
)
suspend fun hlsYield(qualities: List<M3u8Stream>, startIndex: Int = 0): Iterator<HlsDownloadData> {
suspend fun hlsYield(
qualities: List<M3u8Stream>,
startIndex: Int = 0
): Iterator<HlsDownloadData> {
if (qualities.isEmpty()) return listOf(
HlsDownloadData(
byteArrayOf(),

View File

@ -1,131 +1,131 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
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">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/player_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:keepScreenOn="true"
android:orientation="horizontal"
android:screenOrientation="sensorLandscape"
app:backgroundTint="@android:color/black"
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"
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:auto_show="true"
app:controller_layout_id="@layout/player_custom_layout_tv"
app:hide_on_touch="false"
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" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:show_timeout="0" />
<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">
android:id="@+id/player_loading_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:backgroundTint="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.button.MaterialButton
android:nextFocusUp="@id/player_loading_go_back"
android:nextFocusLeft="@id/player_loading_go_back"
android:id="@+id/overlay_loading_skip_button"
style="@style/VideoButtonTV"
tools:visibility="visible"
android:visibility="gone"
android:layout_marginTop="70dp"
android:layout_gravity="center"
android:id="@+id/overlay_loading_skip_button"
android:text="@string/skip_loading"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="70dp"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:nextFocusLeft="@id/player_loading_go_back"
android:nextFocusUp="@id/player_loading_go_back"
android:text="@string/skip_loading"
app:icon="@drawable/ic_baseline_skip_next_24"
style="@style/VideoButtonTV"
android:layout_width="wrap_content" />
android:visibility="gone"
app:icon="@drawable/ic_baseline_skip_next_24"
tools:visibility="visible" />
<ProgressBar
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:id="@+id/main_load" />
android:id="@+id/main_load"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center" />
<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">
android:id="@+id/video_go_back_holder_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: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
android:nextFocusRight="@id/overlay_loading_skip_button"
android:nextFocusDown="@id/overlay_loading_skip_button"
android:focusableInTouchMode="true"
android:id="@+id/player_loading_go_back"
android:layout_width="70dp"
android:layout_height="70dp"
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" />
android:layout_gravity="center"
android:background="@drawable/video_tap_button_always_white"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:nextFocusRight="@id/overlay_loading_skip_button"
android:nextFocusDown="@id/overlay_loading_skip_button" />
</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:id="@+id/player_torrent_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/video_torrent_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="start"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="78% at 18kb/s" />
<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
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" />
android:id="@+id/video_torrent_seeders"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:gravity="start"
android:textColor="@color/white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_video_title"
tools:text="17 seeders" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,24 @@
<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">
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"
android:tag="television"
tools:orientation="vertical">
<FrameLayout
android:id="@+id/subtitle_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
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" />
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"
@ -56,40 +56,40 @@
-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/player_video_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
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: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="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"
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" />
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
@ -104,262 +104,271 @@
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">
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" />
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:contentDescription="@string/go_back_img_des"
android:src="@drawable/ic_baseline_arrow_back_24"
app:tint="@android:color/white" />
<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" />
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: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: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" />
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">
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" />
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" />
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" />
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" />
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" />
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" />
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">
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:layoutDirection="ltr"
android:orientation="horizontal">
android:id="@+id/player_video_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="ltr"
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: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" />
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" />
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" />
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" />
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">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<LinearLayout
android:id="@+id/player_lock_holder"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
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" />
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_subtitle_offset_btt"
android:nextFocusUp="@id/player_pause_play"
app:icon="@drawable/ic_baseline_speed_24"
tools:text="Speed" />
android:id="@+id/player_speed_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_resize_btt"
android:nextFocusRight="@id/player_subtitle_offset_btt"
android:nextFocusUp="@id/player_pause_play"
app:icon="@drawable/ic_baseline_speed_24"
tools:text="Speed" />
<com.google.android.material.button.MaterialButton
android:visibility="gone"
tools:visibility="visible"
android:id="@+id/player_subtitle_offset_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_speed_btt"
android:id="@+id/player_subtitle_offset_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_speed_btt"
android:nextFocusRight="@id/player_sources_btt"
android:text="@string/subtitle_offset"
android:nextFocusRight="@id/player_sources_btt"
app:icon="@drawable/ic_outline_subtitles_24"
android:text="@string/subtitle_offset"/>
android:visibility="gone"
app:icon="@drawable/ic_outline_subtitles_24"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/player_sources_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_subtitle_offset_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" />
android:id="@+id/player_sources_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_subtitle_offset_btt"
android:nextFocusRight="@id/player_tracks_btt"
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" />
android:id="@+id/player_tracks_btt"
style="@style/VideoButtonTV"
android:nextFocusLeft="@id/player_sources_btt"
android:nextFocusRight="@id/player_skip_op"
android:nextFocusUp="@id/player_pause_play"
android:text="@string/tracks"
app:icon="@drawable/ic_baseline_playlist_play_24" />
<com.google.android.material.button.MaterialButton
android:id="@+id/player_skip_episode"
style="@style/VideoButtonTV"
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" />
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" />
<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>
</HorizontalScrollView>
</LinearLayout>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="60dp"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/video_tracks_holder"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="50"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_marginTop="10dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingTop="10dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingBottom="10dp"
android:text="@string/video_tracks"
android:textColor="?attr/textColor"
android:textSize="20sp"
android:textStyle="bold" />
<ListView
android:requiresFadingEdge="vertical"
android:id="@+id/video_tracks_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_rowWeight="1"
android:background="?attr/primaryBlackBackground"
android:nextFocusLeft="@id/sort_subtitles"
android:nextFocusRight="@id/apply_btt"
tools:listitem="@layout/sort_bottom_single_choice" />
</LinearLayout>
<LinearLayout
android:id="@+id/audio_tracks_holder"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="50"
android:orientation="vertical">
<!-- android:id="@+id/subs_settings" android:foreground="?android:attr/selectableItemBackgroundBorderless"
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<LinearLayout
android:foreground="?attr/selectableItemBackgroundBorderless"
android:id="@+id/subtitles_click_settings"
android:layout_rowWeight="1"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:text="@string/audio_tracks"
android:textColor="?attr/textColor"
android:textSize="20sp"
android:textStyle="bold" />
<!-- <TextView-->
<!-- android:textSize="15sp"-->
<!-- android:id="@+id/subtitles_encoding_format"-->
<!-- android:textColor="?attr/textColor"-->
<!-- android:layout_gravity="center"-->
<!-- android:gravity="center"-->
<!-- tools:text="Thai (TIS 620-2533/ISO 8859-11)"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content" />-->
</LinearLayout>
<ImageView
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginTop="0dp"
android:layout_marginEnd="10dp"
android:contentDescription="@string/home_change_provider_img_des"
android:src="@drawable/ic_outline_settings_24"
android:visibility="gone" />
</LinearLayout>
<ListView
android:requiresFadingEdge="vertical"
android:id="@+id/auto_tracks_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_rowWeight="1"
android:background="?attr/primaryBlackBackground"
android:nextFocusLeft="@id/sort_providers"
android:nextFocusRight="@id/cancel_btt"
tools:listfooter="@layout/sort_bottom_footer_add_choice"
tools:listitem="@layout/sort_bottom_single_choice" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/apply_btt_holder"
android:orientation="horizontal"
android:layout_gravity="bottom"
android:gravity="bottom|end"
android:layout_marginTop="-60dp"
android:layout_width="match_parent"
android:layout_height="60dp">
<com.google.android.material.button.MaterialButton
style="@style/WhiteButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_apply"
android:id="@+id/apply_btt"
android:layout_width="wrap_content" />
<com.google.android.material.button.MaterialButton
style="@style/BlackButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_cancel"
android:id="@+id/cancel_btt"
android:layout_width="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -609,5 +609,8 @@
<string name="download_all_plugins_from_repo">Download all plugins from this repository?</string>
<string name="single_plugin_disabled" formatted="true">%s (Disabled)</string>
<string name="tracks">Tracks</string>
<string name="audio_tracks">Audio tracks</string>
<string name="video_tracks">Video tracks</string>
<string name="apply_on_restart">Apply on Restart</string>
</resources>