mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
preview seekbar
This commit is contained in:
parent
bb8cbb5167
commit
bd05a67f26
12 changed files with 413 additions and 57 deletions
|
@ -258,6 +258,8 @@ dependencies {
|
||||||
|
|
||||||
// color palette for images -> colors
|
// color palette for images -> colors
|
||||||
implementation("androidx.palette:palette-ktx:1.0.0")
|
implementation("androidx.palette:palette-ktx:1.0.0")
|
||||||
|
// seekbar https://github.com/rubensousa/PreviewSeekBar
|
||||||
|
implementation("com.github.rubensousa:previewseekbar-media3:1.1.1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("androidSourcesJar", Jar::class) {
|
tasks.register("androidSourcesJar", Jar::class) {
|
||||||
|
|
|
@ -18,10 +18,9 @@ import android.widget.ProgressBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.session.MediaSession
|
import androidx.media3.session.MediaSession
|
||||||
|
@ -30,6 +29,10 @@ import androidx.media3.ui.DefaultTimeBar
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
import androidx.media3.ui.SubtitleView
|
import androidx.media3.ui.SubtitleView
|
||||||
import androidx.media3.ui.TimeBar
|
import androidx.media3.ui.TimeBar
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
|
import com.github.rubensousa.previewseekbar.PreviewBar
|
||||||
|
import com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
|
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
|
||||||
|
@ -454,6 +457,41 @@ abstract class AbstractPlayerFragment(
|
||||||
)
|
)
|
||||||
|
|
||||||
if (player is CS3IPlayer) {
|
if (player is CS3IPlayer) {
|
||||||
|
// preview bar
|
||||||
|
val progressBar : PreviewTimeBar? = playerView?.findViewById(R.id.exo_progress)
|
||||||
|
val previewImageView : ImageView? = playerView?.findViewById(R.id.previewImageView)
|
||||||
|
val previewFrameLayout : FrameLayout? = playerView?.findViewById(R.id.previewFrameLayout)
|
||||||
|
if(progressBar != null && previewImageView != null && previewFrameLayout != null) {
|
||||||
|
var resume = false
|
||||||
|
progressBar.addOnScrubListener(object : PreviewBar.OnScrubListener {
|
||||||
|
override fun onScrubStart(previewBar: PreviewBar?) {
|
||||||
|
progressBar.isPreviewEnabled = player.hasPreview()
|
||||||
|
resume = player.getIsPlaying()
|
||||||
|
if (resume) player.handleEvent(
|
||||||
|
CSPlayerEvent.Pause,
|
||||||
|
PlayerEventSource.Player
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScrubMove(
|
||||||
|
previewBar: PreviewBar?,
|
||||||
|
progress: Int,
|
||||||
|
fromUser: Boolean
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScrubStop(previewBar: PreviewBar?) {
|
||||||
|
if (resume) player.handleEvent(CSPlayerEvent.Play, PlayerEventSource.Player)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
progressBar.attachPreviewView(previewFrameLayout)
|
||||||
|
progressBar.setPreviewLoader { currentPosition, max ->
|
||||||
|
val bitmap = player.getPreview(currentPosition.toFloat().div(max.toFloat()))
|
||||||
|
previewImageView.isGone = bitmap == null
|
||||||
|
previewImageView.setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subView = playerView?.findViewById(R.id.exo_subtitles)
|
subView = playerView?.findViewById(R.id.exo_subtitles)
|
||||||
subStyle = SubtitlesFragment.getCurrentSavedStyle()
|
subStyle = SubtitlesFragment.getCurrentSavedStyle()
|
||||||
player.initSubtitles(subView, subtitleHolder, subStyle)
|
player.initSubtitles(subView, subtitleHolder, subStyle)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
@ -88,7 +89,9 @@ class CS3IPlayer : IPlayer {
|
||||||
private var exoPlayer: ExoPlayer? = null
|
private var exoPlayer: ExoPlayer? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
// If the old value is not null then the player has not been properly released.
|
// If the old value is not null then the player has not been properly released.
|
||||||
debugAssert({ field != null && value != null }, { "Previous player instance should be released!" })
|
debugAssert(
|
||||||
|
{ field != null && value != null },
|
||||||
|
{ "Previous player instance should be released!" })
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +99,8 @@ class CS3IPlayer : IPlayer {
|
||||||
var simpleCacheSize = 0L
|
var simpleCacheSize = 0L
|
||||||
var videoBufferMs = 0L
|
var videoBufferMs = 0L
|
||||||
|
|
||||||
|
private val imageGenerator = PreviewGenerator()
|
||||||
|
|
||||||
private val seekActionTime = 30000L
|
private val seekActionTime = 30000L
|
||||||
|
|
||||||
private var ignoreSSL: Boolean = true
|
private var ignoreSSL: Boolean = true
|
||||||
|
@ -182,6 +187,14 @@ class CS3IPlayer : IPlayer {
|
||||||
subtitleHelper.initSubtitles(subView, subHolder, style)
|
subtitleHelper.initSubtitles(subView, subHolder, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getPreview(fraction: Float): Bitmap? {
|
||||||
|
return imageGenerator.getPreviewImage(fraction)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasPreview(): Boolean {
|
||||||
|
return imageGenerator.hasPreview()
|
||||||
|
}
|
||||||
|
|
||||||
override fun loadPlayer(
|
override fun loadPlayer(
|
||||||
context: Context,
|
context: Context,
|
||||||
sameEpisode: Boolean,
|
sameEpisode: Boolean,
|
||||||
|
@ -190,7 +203,8 @@ class CS3IPlayer : IPlayer {
|
||||||
startPosition: Long?,
|
startPosition: Long?,
|
||||||
subtitles: Set<SubtitleData>,
|
subtitles: Set<SubtitleData>,
|
||||||
subtitle: SubtitleData?,
|
subtitle: SubtitleData?,
|
||||||
autoPlay: Boolean?
|
autoPlay: Boolean?,
|
||||||
|
preview : Boolean,
|
||||||
) {
|
) {
|
||||||
Log.i(TAG, "loadPlayer")
|
Log.i(TAG, "loadPlayer")
|
||||||
if (sameEpisode) {
|
if (sameEpisode) {
|
||||||
|
@ -210,9 +224,27 @@ class CS3IPlayer : IPlayer {
|
||||||
// release the current exoplayer and cache
|
// release the current exoplayer and cache
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
if (link != null) {
|
if (link != null) {
|
||||||
|
// only video support atm
|
||||||
|
if (link.type == ExtractorLinkType.VIDEO && preview) {
|
||||||
|
val headers = if (link.referer.isBlank()) {
|
||||||
|
link.headers
|
||||||
|
} else {
|
||||||
|
mapOf("referer" to link.referer) + link.headers
|
||||||
|
}
|
||||||
|
imageGenerator.load(sameEpisode, link.url, headers)
|
||||||
|
} else {
|
||||||
|
imageGenerator.clear(sameEpisode)
|
||||||
|
}
|
||||||
loadOnlinePlayer(context, link)
|
loadOnlinePlayer(context, link)
|
||||||
} else if (data != null) {
|
} else if (data != null) {
|
||||||
|
if (preview) {
|
||||||
|
imageGenerator.load(sameEpisode, context, data.uri)
|
||||||
|
} else {
|
||||||
|
imageGenerator.clear(sameEpisode)
|
||||||
|
}
|
||||||
loadOfflinePlayer(context, data)
|
loadOfflinePlayer(context, data)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException("Requires link or uri")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +526,7 @@ class CS3IPlayer : IPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun release() {
|
override fun release() {
|
||||||
|
imageGenerator.release()
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,8 +904,20 @@ class CS3IPlayer : IPlayer {
|
||||||
|
|
||||||
CSPlayerEvent.SeekForward -> seekTime(seekActionTime, source)
|
CSPlayerEvent.SeekForward -> seekTime(seekActionTime, source)
|
||||||
CSPlayerEvent.SeekBack -> seekTime(-seekActionTime, source)
|
CSPlayerEvent.SeekBack -> seekTime(-seekActionTime, source)
|
||||||
CSPlayerEvent.NextEpisode -> event(EpisodeSeekEvent(offset = 1, source = source))
|
CSPlayerEvent.NextEpisode -> event(
|
||||||
CSPlayerEvent.PrevEpisode -> event(EpisodeSeekEvent(offset = -1, source = source))
|
EpisodeSeekEvent(
|
||||||
|
offset = 1,
|
||||||
|
source = source
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
CSPlayerEvent.PrevEpisode -> event(
|
||||||
|
EpisodeSeekEvent(
|
||||||
|
offset = -1,
|
||||||
|
source = source
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
CSPlayerEvent.SkipCurrentChapter -> {
|
CSPlayerEvent.SkipCurrentChapter -> {
|
||||||
//val dur = this@CS3IPlayer.getDuration() ?: return@apply
|
//val dur = this@CS3IPlayer.getDuration() ?: return@apply
|
||||||
getCurrentTimestamp()?.let { lastTimeStamp ->
|
getCurrentTimestamp()?.let { lastTimeStamp ->
|
||||||
|
|
|
@ -180,6 +180,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
(if (sameEpisode) currentSelectedSubtitles else null) ?: getAutoSelectSubtitle(
|
(if (sameEpisode) currentSelectedSubtitles else null) ?: getAutoSelectSubtitle(
|
||||||
currentSubs, settings = true, downloads = true
|
currentSubs, settings = true, downloads = true
|
||||||
),
|
),
|
||||||
|
preview = isFullScreenPlayer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.ui.player
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.util.Rational
|
import android.util.Rational
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||||
import com.lagradost.cloudstream3.utils.EpisodeSkip
|
import com.lagradost.cloudstream3.utils.EpisodeSkip
|
||||||
|
@ -246,11 +247,15 @@ interface IPlayer {
|
||||||
startPosition: Long? = null,
|
startPosition: Long? = null,
|
||||||
subtitles: Set<SubtitleData>,
|
subtitles: Set<SubtitleData>,
|
||||||
subtitle: SubtitleData?,
|
subtitle: SubtitleData?,
|
||||||
autoPlay: Boolean? = true
|
autoPlay: Boolean? = true,
|
||||||
|
preview : Boolean = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun reloadPlayer(context: Context)
|
fun reloadPlayer(context: Context)
|
||||||
|
|
||||||
|
fun getPreview(fraction : Float) : Bitmap?
|
||||||
|
fun hasPreview() : Boolean
|
||||||
|
|
||||||
fun setActiveSubtitles(subtitles: Set<SubtitleData>)
|
fun setActiveSubtitles(subtitles: Set<SubtitleData>)
|
||||||
fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean // returns true if the player requires a reload, null for nothing
|
fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean // returns true if the player requires a reload, null for nothing
|
||||||
fun getCurrentPreferredSubtitle(): SubtitleData?
|
fun getCurrentPreferredSubtitle(): SubtitleData?
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.media.MediaMetadataRetriever
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.log2
|
||||||
|
|
||||||
|
const val MAX_LOD = 6
|
||||||
|
const val MIN_LOD = 3
|
||||||
|
|
||||||
|
class PreviewGenerator {
|
||||||
|
// lod = level of detail where the number indicates how many ones there is
|
||||||
|
// 2^(lod-1) = images
|
||||||
|
private var loadedLod = 0
|
||||||
|
private var loadedImages = 0
|
||||||
|
private var images = Array<Bitmap?>((1 shl MAX_LOD) - 1) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasPreview(): Boolean {
|
||||||
|
synchronized(images) {
|
||||||
|
return loadedLod >= MIN_LOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val TAG = "PreviewImg"
|
||||||
|
|
||||||
|
fun getPreviewImage(fraction: Float): Bitmap? {
|
||||||
|
synchronized(images) {
|
||||||
|
if (loadedLod < MIN_LOD) {
|
||||||
|
Log.i(TAG, "Requesting preview for $fraction but $loadedLod < $MIN_LOD")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Requesting preview for $fraction")
|
||||||
|
|
||||||
|
var bestIdx = 0
|
||||||
|
var bestDiff = 0.5f.minus(fraction).absoluteValue
|
||||||
|
|
||||||
|
// this should be done mathematically, but for now we just loop all images
|
||||||
|
for (l in 1..loadedLod + 1) {
|
||||||
|
val items = (1 shl (l - 1))
|
||||||
|
for (i in 0 until items) {
|
||||||
|
val idx = items - 1 + i
|
||||||
|
if (idx > loadedImages) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val currentFraction =
|
||||||
|
(1.0f.div((1 shl l).toFloat()) + i * 1.0f.div(items.toFloat()))
|
||||||
|
val diff = currentFraction.minus(fraction).absoluteValue
|
||||||
|
if (diff < bestDiff) {
|
||||||
|
bestDiff = diff
|
||||||
|
bestIdx = idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Best diff found at ${bestDiff * 100}% diff (${bestIdx})")
|
||||||
|
return images[bestIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also check out https://github.com/wseemann/FFmpegMediaMetadataRetriever
|
||||||
|
private val retriever: MediaMetadataRetriever = MediaMetadataRetriever()
|
||||||
|
|
||||||
|
fun clear(keepCache: Boolean = false) {
|
||||||
|
if (keepCache) return
|
||||||
|
synchronized(images) {
|
||||||
|
loadedLod = 0
|
||||||
|
loadedImages = 0
|
||||||
|
images.fill(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var currentJob: Job? = null
|
||||||
|
fun load(keepCache: Boolean, url: String, headers: Map<String, String>) {
|
||||||
|
currentJob?.cancel()
|
||||||
|
currentJob = ioSafe {
|
||||||
|
Log.i(TAG, "Loading with url = $url headers = $headers")
|
||||||
|
clear(keepCache)
|
||||||
|
retriever.setDataSource(url, headers)
|
||||||
|
start(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load(keepCache: Boolean, context: Context, uri: Uri) {
|
||||||
|
currentJob?.cancel()
|
||||||
|
currentJob = ioSafe {
|
||||||
|
Log.i(TAG, "Loading with uri = $uri")
|
||||||
|
clear(keepCache)
|
||||||
|
retriever.setDataSource(context, uri)
|
||||||
|
start(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun release() {
|
||||||
|
currentJob?.cancel()
|
||||||
|
clear(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
@WorkerThread
|
||||||
|
private fun start(scope: CoroutineScope) {
|
||||||
|
Log.i(TAG, "Started loading preview")
|
||||||
|
|
||||||
|
val durationMs =
|
||||||
|
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
|
||||||
|
?: throw IllegalArgumentException("Bad video duration")
|
||||||
|
val durationUs = (durationMs * 1000L).toFloat()
|
||||||
|
//val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: throw IllegalArgumentException("Bad video width")
|
||||||
|
//val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: throw IllegalArgumentException("Bad video height")
|
||||||
|
|
||||||
|
// log2 # 10s durations in the video ~= how many segments we have
|
||||||
|
val maxLod = ceil(log2((durationMs / 10_000).toFloat())).toInt().coerceIn(MIN_LOD, MAX_LOD)
|
||||||
|
|
||||||
|
for (l in 1..maxLod) {
|
||||||
|
val items = (1 shl (l - 1))
|
||||||
|
for (i in 0 until items) {
|
||||||
|
val idx = items - 1 + i // as sum(prev) = cur-1
|
||||||
|
// frame = 100 / 2^lod + i * 100 / 2^(lod-1) = duration % where lod is one indexed
|
||||||
|
val fraction = (1.0f.div((1 shl l).toFloat()) + i * 1.0f.div(items.toFloat()))
|
||||||
|
Log.i(TAG, "Generating preview for ${fraction * 100}%")
|
||||||
|
val frame = durationUs * fraction
|
||||||
|
val img = retriever.getFrameAtTime(
|
||||||
|
frame.toLong(),
|
||||||
|
MediaMetadataRetriever.OPTION_CLOSEST_SYNC
|
||||||
|
)
|
||||||
|
if (!scope.isActive) return
|
||||||
|
synchronized(images) {
|
||||||
|
images[idx] = img
|
||||||
|
loadedImages = maxOf(loadedImages,idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized(images) {
|
||||||
|
loadedLod = maxOf(loadedLod, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -151,7 +151,8 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
startPosition = 0L,
|
startPosition = 0L,
|
||||||
subtitles = emptySet(),
|
subtitles = emptySet(),
|
||||||
subtitle = null,
|
subtitle = null,
|
||||||
autoPlay = false
|
autoPlay = false,
|
||||||
|
preview = false
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
} ?: run {
|
} ?: run {
|
||||||
|
|
10
app/src/main/res/drawable/video_frame.xml
Normal file
10
app/src/main/res/drawable/video_frame.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/video_frame_width"
|
||||||
|
android:color="@android:color/white" />
|
||||||
|
|
||||||
|
<solid android:color="@android:color/black" />
|
||||||
|
</shape>
|
|
@ -86,7 +86,6 @@
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
<!-- atm this is useless, however it might be used for PIP one day? -->
|
<!-- atm this is useless, however it might be used for PIP one day? -->
|
||||||
<ImageView
|
<ImageView
|
||||||
android:visibility="gone"
|
|
||||||
android:id="@+id/player_fullscreen"
|
android:id="@+id/player_fullscreen"
|
||||||
android:layout_width="30dp"
|
android:layout_width="30dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
|
@ -94,7 +93,9 @@
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="20dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/baseline_fullscreen_24"
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
android:visibility="gone"
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/player_intro_play"
|
android:id="@+id/player_intro_play"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -108,8 +109,8 @@
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:visibility="gone"
|
android:importantForAccessibility="no"
|
||||||
android:importantForAccessibility="no" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
@ -117,6 +118,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/player_top_holder"
|
android:id="@+id/player_top_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -272,6 +274,7 @@
|
||||||
app:tint="@color/white"
|
app:tint="@color/white"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/player_pause_play_holder_holder"
|
android:id="@+id/player_pause_play_holder_holder"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
|
@ -298,6 +301,7 @@
|
||||||
app:tint="@color/white"
|
app:tint="@color/white"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/player_ffwd_holder"
|
android:id="@+id/player_ffwd_holder"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -427,7 +431,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_bar"
|
android:id="@+id/player_video_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -437,10 +441,10 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_position"
|
android:id="@id/exo_position"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
android:gravity="end"
|
android:gravity="end|center_vertical"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="4dp"
|
android:paddingLeft="4dp"
|
||||||
|
@ -448,14 +452,46 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
tools:text="15:30" />
|
tools:text="15:30" />
|
||||||
<!--app:buffered_color="@color/videoCache"-->
|
|
||||||
<androidx.media3.ui.DefaultTimeBar
|
<FrameLayout
|
||||||
|
android:id="@+id/previewFrameLayout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@drawable/video_frame"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/exo_progress"
|
||||||
|
app:layout_constraintDimensionRatio="16:9"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintWidth_default="percent"
|
||||||
|
app:layout_constraintWidth_percent="0.25"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/previewImageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="@dimen/video_frame_width"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
app:bar_height="2dp"
|
app:bar_height="2dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/exo_duration"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/exo_position"
|
||||||
app:played_color="?attr/colorPrimary"
|
app:played_color="?attr/colorPrimary"
|
||||||
|
|
||||||
app:scrubber_color="?attr/colorPrimary"
|
app:scrubber_color="?attr/colorPrimary"
|
||||||
|
@ -463,12 +499,12 @@
|
||||||
app:scrubber_enabled_size="24dp"
|
app:scrubber_enabled_size="24dp"
|
||||||
app:unplayed_color="@color/videoProgress" />
|
app:unplayed_color="@color/videoProgress" />
|
||||||
|
|
||||||
<!-- exo_duration-->
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_duration"
|
android:id="@id/exo_duration"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center|center_vertical"
|
||||||
|
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="20dp"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
|
@ -477,9 +513,10 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:text="23:20" />
|
tools:text="23:20" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -503,13 +503,12 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_bar"
|
android:id="@+id/player_video_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layoutDirection="ltr"
|
android:layoutDirection="ltr"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/player_pause_play"
|
android:id="@+id/player_pause_play"
|
||||||
|
|
||||||
|
@ -526,14 +525,17 @@
|
||||||
|
|
||||||
android:tag="@string/tv_no_focus_tag"
|
android:tag="@string/tv_no_focus_tag"
|
||||||
app:tint="@color/player_button_tv"
|
app:tint="@color/player_button_tv"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_position"
|
android:id="@id/exo_position"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:gravity="end"
|
android:layout_marginStart="20dp"
|
||||||
|
android:gravity="end|center_vertical"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="4dp"
|
android:paddingLeft="4dp"
|
||||||
|
@ -541,29 +543,59 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/player_pause_play"
|
||||||
tools:text="15:30" />
|
tools:text="15:30" />
|
||||||
<!--app:buffered_color="@color/videoCache"-->
|
|
||||||
<androidx.media3.ui.DefaultTimeBar
|
<FrameLayout
|
||||||
|
android:id="@+id/previewFrameLayout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@drawable/video_frame"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/exo_progress"
|
||||||
|
app:layout_constraintDimensionRatio="16:9"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintWidth_default="percent"
|
||||||
|
app:layout_constraintWidth_percent="0.25"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/previewImageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="@dimen/video_frame_width"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:focusable="false"
|
|
||||||
android:focusableInTouchMode="false"
|
|
||||||
app:bar_height="2dp"
|
app:bar_height="2dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/exo_duration"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/exo_position"
|
||||||
app:played_color="?attr/colorPrimary"
|
app:played_color="?attr/colorPrimary"
|
||||||
|
|
||||||
app:scrubber_color="?attr/colorPrimary"
|
app:scrubber_color="?attr/colorPrimary"
|
||||||
app:scrubber_dragged_size="26dp"
|
app:scrubber_dragged_size="26dp"
|
||||||
app:scrubber_enabled_size="24dp"
|
app:scrubber_enabled_size="24dp"
|
||||||
app:unplayed_color="@color/videoProgress" />
|
app:unplayed_color="@color/videoProgress" />
|
||||||
|
|
||||||
<!-- exo_duration-->
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_duration"
|
android:id="@id/exo_duration"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center|center_vertical"
|
||||||
|
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="20dp"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
|
@ -572,9 +604,11 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:text="23:20" />
|
tools:text="23:20" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -212,7 +212,6 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_center_menu"
|
android:id="@+id/player_center_menu"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -294,6 +293,7 @@
|
||||||
app:tint="@color/white"
|
app:tint="@color/white"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/player_ffwd_holder"
|
android:id="@+id/player_ffwd_holder"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -420,20 +420,20 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_bar"
|
android:id="@+id/player_video_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layoutDirection="ltr"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_position"
|
android:id="@id/exo_position"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
android:gravity="end"
|
android:gravity="end|center_vertical"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="4dp"
|
android:paddingLeft="4dp"
|
||||||
|
@ -441,14 +441,46 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
tools:text="15:30" />
|
tools:text="15:30" />
|
||||||
<!--app:buffered_color="@color/videoCache"-->
|
|
||||||
<androidx.media3.ui.DefaultTimeBar
|
<FrameLayout
|
||||||
|
android:id="@+id/previewFrameLayout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@drawable/video_frame"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/exo_progress"
|
||||||
|
app:layout_constraintDimensionRatio="16:9"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintWidth_default="percent"
|
||||||
|
app:layout_constraintWidth_percent="0.25"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/previewImageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="@dimen/video_frame_width"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
app:bar_height="2dp"
|
app:bar_height="2dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/exo_duration"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/exo_position"
|
||||||
app:played_color="?attr/colorPrimary"
|
app:played_color="?attr/colorPrimary"
|
||||||
|
|
||||||
app:scrubber_color="?attr/colorPrimary"
|
app:scrubber_color="?attr/colorPrimary"
|
||||||
|
@ -456,13 +488,13 @@
|
||||||
app:scrubber_enabled_size="24dp"
|
app:scrubber_enabled_size="24dp"
|
||||||
app:unplayed_color="@color/videoProgress" />
|
app:unplayed_color="@color/videoProgress" />
|
||||||
|
|
||||||
<!-- exo_duration-->
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/exo_duration"
|
android:id="@id/exo_duration"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center|center_vertical"
|
||||||
android:layout_marginEnd="20dp"
|
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="4dp"
|
android:paddingLeft="4dp"
|
||||||
|
@ -470,19 +502,23 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/exo_position"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/player_fullscreen"
|
||||||
tools:text="23:20" />
|
tools:text="23:20" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/player_fullscreen"
|
android:id="@+id/player_fullscreen"
|
||||||
android:layout_width="30dp"
|
android:layout_width="30dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="20dp"
|
||||||
|
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/baseline_fullscreen_24"
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -19,5 +19,5 @@
|
||||||
<dimen name="navbar_width">62dp</dimen>
|
<dimen name="navbar_width">62dp</dimen>
|
||||||
|
|
||||||
<dimen name="download_size">50dp</dimen>
|
<dimen name="download_size">50dp</dimen>
|
||||||
|
<dimen name="video_frame_width">1dp</dimen>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue