mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Add audio and video track support (#69)
* Add audio and video track support
This commit is contained in:
		
							parent
							
								
									7a68d6304f
								
							
						
					
					
						commit
						461f3d75d8
					
				
					 12 changed files with 1283 additions and 809 deletions
				
			
		|  | @ -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) { | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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?) | ||||
| } | ||||
|  | @ -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() {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(), | ||||
|  |  | |||
|  | @ -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
											
										
									
								
							|  | @ -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> | ||||
|  |  | |||
							
								
								
									
										148
									
								
								app/src/main/res/layout/player_select_tracks.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								app/src/main/res/layout/player_select_tracks.xml
									
										
									
									
									
										Normal 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> | ||||
|  | @ -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> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue