make chapters visible in the seekbar
This commit is contained in:
parent
8a3cc12bd7
commit
430bed20b6
|
@ -81,7 +81,7 @@ data class VideoPlayerUIState(
|
|||
seekerPosition = 0.3f,
|
||||
bufferedPercentage = 0.5f,
|
||||
isLoading = false,
|
||||
durationInMs = 420,
|
||||
durationInMs = 12000,
|
||||
playbackPositionInPlaylistS = 5039,
|
||||
playbackPositionInMs = 69,
|
||||
fastSeekSeconds = 10,
|
||||
|
@ -92,6 +92,11 @@ data class VideoPlayerUIState(
|
|||
currentlyPlaying = PlaylistItem.DUMMY,
|
||||
currentPlaylistItemIndex = 1,
|
||||
chapters = arrayListOf(
|
||||
Chapter(
|
||||
chapterStartInMs = 0,
|
||||
chapterTitle = "Intro",
|
||||
thumbnail = null
|
||||
),
|
||||
Chapter(
|
||||
chapterStartInMs = 5000,
|
||||
chapterTitle = "First Chapter",
|
||||
|
@ -102,11 +107,6 @@ data class VideoPlayerUIState(
|
|||
chapterTitle = "Second Chapter",
|
||||
thumbnail = null
|
||||
),
|
||||
Chapter(
|
||||
chapterStartInMs = 20000,
|
||||
chapterTitle = "Third Chapter",
|
||||
thumbnail = null
|
||||
)
|
||||
),
|
||||
playList = arrayListOf(
|
||||
PlaylistItem(
|
||||
|
|
|
@ -42,7 +42,7 @@ interface VideoPlayerViewModel {
|
|||
fun pause()
|
||||
fun prevStream()
|
||||
fun nextStream()
|
||||
fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig)
|
||||
fun switchToFullscreen()
|
||||
fun switchToEmbeddedView()
|
||||
fun onBackPressed()
|
||||
fun showUi()
|
||||
|
@ -54,7 +54,7 @@ interface VideoPlayerViewModel {
|
|||
fun finishFastSeek()
|
||||
fun brightnessChange(changeRate: Float, systemBrightness: Float)
|
||||
fun volumeChange(changeRate: Float)
|
||||
fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig)
|
||||
fun openStreamSelection(selectChapter: Boolean)
|
||||
fun closeStreamSelection()
|
||||
fun chapterSelected(chapterId: Int)
|
||||
fun streamSelected(streamId: Int)
|
||||
|
|
|
@ -432,11 +432,8 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig) {
|
||||
override fun openStreamSelection(selectChapter: Boolean) {
|
||||
uiVisibilityJob?.cancel()
|
||||
if (!uiState.value.uiMode.fullscreen) {
|
||||
this.embeddedUiConfig = embeddedUiConfig
|
||||
}
|
||||
updateUiMode(
|
||||
if (selectChapter) uiState.value.uiMode.getChapterSelectUiState()
|
||||
else uiState.value.uiMode.getStreamSelectUiState()
|
||||
|
@ -469,11 +466,10 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig) {
|
||||
override fun switchToFullscreen() {
|
||||
uiVisibilityJob?.cancel()
|
||||
finishFastSeek()
|
||||
|
||||
this.embeddedUiConfig = embeddedUiConfig
|
||||
updateUiMode(UIModeState.FULLSCREEN_VIDEO)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
|||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun switchToFullscreen(embeddedUiConfig: EmbeddedUiConfig) {
|
||||
override fun switchToFullscreen() {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
|||
}
|
||||
|
||||
override fun fastSeek(steps: Int) {
|
||||
println("dummy impl")
|
||||
println("dummy impl, steps: $steps")
|
||||
}
|
||||
|
||||
override fun finishFastSeek() {
|
||||
|
@ -76,7 +76,7 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
|||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig) {
|
||||
override fun openStreamSelection(selectChapter: Boolean) {
|
||||
println("dummy impl")
|
||||
}
|
||||
|
||||
|
|
|
@ -36,11 +36,8 @@ import androidx.compose.foundation.interaction.Interaction
|
|||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.requiredSizeIn
|
||||
|
@ -49,8 +46,6 @@ import androidx.compose.foundation.layout.widthIn
|
|||
import androidx.compose.foundation.progressSemantics
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
|
@ -75,7 +70,6 @@ import androidx.compose.ui.graphics.drawscope.rotateRad
|
|||
import androidx.compose.ui.graphics.drawscope.translate
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.VerticalAlignmentLine
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.semantics.disabled
|
||||
|
@ -135,18 +129,25 @@ fun Seeker(
|
|||
onValueChange: (Float) -> Unit,
|
||||
onValueChangeFinished: (() -> Unit)? = null,
|
||||
segments: List<Segment> = emptyList(),
|
||||
chapterSegments: List<ChapterSegment> = emptyList(),
|
||||
enabled: Boolean = true,
|
||||
colors: SeekerColors = SeekerDefaults.seekerColors(),
|
||||
dimensions: SeekerDimensions = SeekerDefaults.seekerDimensions(),
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
if (segments.isNotEmpty()) {
|
||||
require(segments.first().start == range.start) {
|
||||
"the first segment should start from range start value"
|
||||
}
|
||||
segments.forEach {
|
||||
require(it.start in range && it.end in range) {
|
||||
"segment must lie withing the range: segment: ${it.name} start: ${it.start}, end: ${it.end}, range: ${range}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (chapterSegments.isNotEmpty()) {
|
||||
chapterSegments.forEach {
|
||||
require(it.start in range) {
|
||||
"segment must start from withing the range."
|
||||
"chapter segment must lie withing the range: segment: ${it.name} start: ${it.start} range: ${range}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +179,10 @@ fun Seeker(
|
|||
segmentToPxValues(segments, range, widthPx)
|
||||
}
|
||||
|
||||
val chapterSegmentsPx = remember(chapterSegments, range, widthPx) {
|
||||
chapterSegmentToPxValues(chapterSegments, range, widthPx)
|
||||
}
|
||||
|
||||
LaunchedEffect(thumbValue, segments) {
|
||||
state.currentSegment(thumbValue, segments)
|
||||
}
|
||||
|
@ -259,6 +264,7 @@ fun Seeker(
|
|||
readAheadValuePx = readAheadValuePx,
|
||||
enabled = enabled,
|
||||
segments = segmentStarts,
|
||||
chapterSegments = chapterSegmentsPx,
|
||||
colors = colors,
|
||||
dimensions = dimensions,
|
||||
interactionSource = interactionSource
|
||||
|
@ -276,6 +282,7 @@ private fun Seeker(
|
|||
readAheadValuePx: Float,
|
||||
enabled: Boolean,
|
||||
segments: List<SegmentPxs>,
|
||||
chapterSegments: List<SegmentPxs>,
|
||||
colors: SeekerColors,
|
||||
dimensions: SeekerDimensions,
|
||||
interactionSource: MutableInteractionSource
|
||||
|
@ -288,6 +295,7 @@ private fun Seeker(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
enabled = enabled,
|
||||
segments = segments,
|
||||
chapterSegments = chapterSegments,
|
||||
colors = colors,
|
||||
widthPx = widthPx,
|
||||
valuePx = valuePx,
|
||||
|
@ -310,6 +318,7 @@ private fun Track(
|
|||
modifier: Modifier,
|
||||
enabled: Boolean,
|
||||
segments: List<SegmentPxs>,
|
||||
chapterSegments: List<SegmentPxs>,
|
||||
colors: SeekerColors,
|
||||
widthPx: Float,
|
||||
valuePx: Float,
|
||||
|
@ -334,7 +343,7 @@ private fun Track(
|
|||
val left = thumbRadius.toPx()
|
||||
|
||||
translate(left = left) {
|
||||
if (segments.isEmpty()) {
|
||||
|
||||
// draw the track with a single line.
|
||||
drawLine(
|
||||
start = Offset(rtlAware(0f, widthPx, isRtl), center.y),
|
||||
|
@ -343,26 +352,7 @@ private fun Track(
|
|||
strokeWidth = trackHeight.toPx(),
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
} else {
|
||||
// draw segments in their respective color,
|
||||
// excluding gaps (which will be cleared out later)
|
||||
for (index in segments.indices) {
|
||||
val segment = segments[index]
|
||||
val segmentColor = when (segment.color) {
|
||||
Color.Unspecified -> trackColor
|
||||
else -> segment.color
|
||||
}
|
||||
drawSegment(
|
||||
startPx = rtlAware(segment.startPx, widthPx, isRtl),
|
||||
endPx = rtlAware(segment.endPx, widthPx, isRtl),
|
||||
trackColor = segmentColor,
|
||||
trackHeight = trackHeight.toPx(),
|
||||
blendMode = BlendMode.SrcOver,
|
||||
startCap = if (index == 0) StrokeCap.Round else null,
|
||||
endCap = if (index == segments.lastIndex) StrokeCap.Round else null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// readAhead indicator
|
||||
drawLine(
|
||||
|
@ -382,14 +372,28 @@ private fun Track(
|
|||
cap = StrokeCap.Round
|
||||
)
|
||||
|
||||
// clear segment gaps
|
||||
// draw segments in their respective color,
|
||||
for (index in segments.indices) {
|
||||
if (index == segments.lastIndex) break // skip "gap" after last segment
|
||||
val segment = segments[index]
|
||||
drawGap(
|
||||
startPx = rtlAware(segment.endPx - segmentGap.toPx(), widthPx, isRtl),
|
||||
val segmentColor = when (segment.color) {
|
||||
Color.Unspecified -> trackColor
|
||||
else -> segment.color
|
||||
}
|
||||
drawSegment(
|
||||
startPx = rtlAware(segment.startPx, widthPx, isRtl),
|
||||
endPx = rtlAware(segment.endPx, widthPx, isRtl),
|
||||
trackColor = segmentColor,
|
||||
trackHeight = trackHeight.toPx(),
|
||||
blendMode = BlendMode.SrcOver,
|
||||
)
|
||||
}
|
||||
|
||||
// clear segment gaps
|
||||
for (index in chapterSegments.indices) {
|
||||
val segment = chapterSegments[index]
|
||||
drawDot(
|
||||
x = rtlAware(segment.startPx, widthPx, isRtl),
|
||||
trackHeight = trackHeight.toPx()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -485,8 +489,6 @@ private fun DrawScope.drawSegment(
|
|||
trackColor: Color,
|
||||
trackHeight: Float,
|
||||
blendMode: BlendMode,
|
||||
startCap: StrokeCap? = null,
|
||||
endCap: StrokeCap? = null
|
||||
) {
|
||||
drawLine(
|
||||
start = Offset(startPx, center.y),
|
||||
|
@ -494,8 +496,7 @@ private fun DrawScope.drawSegment(
|
|||
color = trackColor,
|
||||
strokeWidth = trackHeight,
|
||||
blendMode = blendMode,
|
||||
endCap = endCap,
|
||||
startCap = startCap
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -513,6 +514,18 @@ private fun DrawScope.drawGap(
|
|||
)
|
||||
}
|
||||
|
||||
private fun DrawScope.drawDot(
|
||||
x: Float,
|
||||
trackHeight: Float
|
||||
) {
|
||||
drawCircle(
|
||||
radius = (trackHeight / 2f) * 0.8f,
|
||||
center = Offset(x = x, y = center.y),
|
||||
color = Color.Gray.copy(alpha = 0.9f),
|
||||
blendMode = BlendMode.SrcOver
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Thumb(
|
||||
valuePx: () -> Float,
|
||||
|
@ -580,14 +593,21 @@ private fun Modifier.progressSemantics(
|
|||
@Composable
|
||||
fun SeekerPreview() {
|
||||
val segments = listOf(
|
||||
Segment(name = "Intro", start = 0f),
|
||||
Segment(name = "Talk 1", start = 0.5f),
|
||||
Segment(name = "Talk 2", start = 0.8f),
|
||||
Segment(name = "Intro", start = 0.1f, end = 0.3f, color = Color.Green),
|
||||
Segment(name = "Talk 1", start = 0.5f, end = 0.6f, color = Color.Cyan),
|
||||
Segment(name = "Talk 2", start = 0.8f, end = 0.85f, color = Color.Blue),
|
||||
)
|
||||
|
||||
val chapterSegments = listOf(
|
||||
ChapterSegment(name = "Intro", start = 0.0f, color = Color.Green),
|
||||
ChapterSegment(name = "Talk 1", start = 0.55f, color = Color.Cyan),
|
||||
ChapterSegment(name = "Talk 2", start = 0.9f, color = Color.Blue),
|
||||
)
|
||||
Seeker(
|
||||
value = 0.7f,
|
||||
range = 0f..1f,
|
||||
segments = segments,
|
||||
chapterSegments = chapterSegments,
|
||||
onValueChange = { },
|
||||
)
|
||||
}
|
|
@ -74,13 +74,25 @@ fun rememberSeekerState(): SeekerState = remember {
|
|||
data class Segment(
|
||||
val name: String,
|
||||
val start: Float,
|
||||
val end: Float,
|
||||
val color: Color = Color.Unspecified
|
||||
) {
|
||||
companion object {
|
||||
val Unspecified = Segment(name = "", start = 0f)
|
||||
val Unspecified = Segment(name = "", start = 0f, end = 0f)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class ChapterSegment(
|
||||
val name: String,
|
||||
val start: Float,
|
||||
val color: Color = Color.Unspecified
|
||||
) {
|
||||
companion object {
|
||||
val Unspecified = ChapterSegment(name = "", start = 0f)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal data class SegmentPxs(
|
||||
val name: String,
|
||||
|
|
|
@ -57,6 +57,37 @@ internal fun segmentToPxValues(
|
|||
|
||||
val rangeSize = range.endInclusive - range.start
|
||||
val sortedSegments = segments.distinct().sortedBy { it.start }
|
||||
val segmentRangesPxs = sortedSegments.map { segment ->
|
||||
|
||||
// percent of the start of this segment in the range size
|
||||
val percentStart = (segment.start - range.start) * 100 / rangeSize
|
||||
val percentEnd = (segment.end - range.start) * 100 / rangeSize
|
||||
val startPx = percentStart * widthPx / 100
|
||||
val endPx = percentEnd * widthPx / 100
|
||||
Pair(startPx, endPx)
|
||||
}
|
||||
|
||||
return sortedSegments.mapIndexed { index, segment ->
|
||||
SegmentPxs(
|
||||
name = segment.name,
|
||||
color = segment.color,
|
||||
startPx = segmentRangesPxs[index].first,
|
||||
endPx = segmentRangesPxs[index].second
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun chapterSegmentToPxValues(
|
||||
segments: List<ChapterSegment>,
|
||||
range: ClosedFloatingPointRange<Float>,
|
||||
widthPx: Float,
|
||||
): List<SegmentPxs> {
|
||||
|
||||
val rangeSize = range.endInclusive - range.start
|
||||
val sortedSegments = ArrayList(segments.distinct().sortedBy { it.start })
|
||||
if(sortedSegments.isNotEmpty()) {
|
||||
sortedSegments.removeAt(0)
|
||||
}
|
||||
val segmentStartPxs = sortedSegments.map { segment ->
|
||||
|
||||
// percent of the start of this segment in the range size
|
||||
|
|
|
@ -23,6 +23,7 @@ package net.newpipe.newplayer.ui.videoplayer
|
|||
import android.app.Activity
|
||||
import android.app.LocaleConfig
|
||||
import android.icu.text.DecimalFormat
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.icons.Icons
|
||||
|
@ -44,21 +45,23 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import net.newpipe.newplayer.Chapter
|
||||
import net.newpipe.newplayer.R
|
||||
import net.newpipe.newplayer.model.UIModeState
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.seeker.ChapterSegment
|
||||
import net.newpipe.newplayer.ui.seeker.DefaultSeekerColor
|
||||
import net.newpipe.newplayer.ui.seeker.Seeker
|
||||
import net.newpipe.newplayer.ui.seeker.SeekerColors
|
||||
import net.newpipe.newplayer.ui.seeker.SeekerDefaults
|
||||
import net.newpipe.newplayer.ui.seeker.Segment
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||
import net.newpipe.newplayer.utils.getLocale
|
||||
import net.newpipe.newplayer.utils.getTimeStringFromMs
|
||||
import java.util.Locale
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
private const val TAG = "BottomUI"
|
||||
|
||||
@Composable
|
||||
fun BottomUI(
|
||||
|
@ -77,17 +80,17 @@ fun BottomUI(
|
|||
onValueChange = viewModel::seekPositionChanged,
|
||||
onValueChangeFinished = viewModel::seekingFinished,
|
||||
readAheadValue = uiState.bufferedPercentage,
|
||||
colors = customizedSeekerColors()
|
||||
colors = customizedSeekerColors(),
|
||||
chapterSegments = getSeekerSegmentsFromChapters(uiState.chapters, uiState.durationInMs)
|
||||
)
|
||||
|
||||
Text(getTimeStringFromMs(uiState.durationInMs, getLocale() ?: locale))
|
||||
|
||||
val embeddedUiConfig = getEmbeddedUiConfig(LocalContext.current as Activity)
|
||||
IconButton(
|
||||
onClick = if (uiState.uiMode.fullscreen) viewModel::switchToEmbeddedView
|
||||
else {
|
||||
{ // <- head of lambda ... yea kotlin is weird
|
||||
viewModel.switchToFullscreen(embeddedUiConfig)
|
||||
viewModel.switchToFullscreen()
|
||||
}
|
||||
}
|
||||
) {
|
||||
|
@ -114,6 +117,21 @@ private fun customizedSeekerColors(): SeekerColors {
|
|||
return colors
|
||||
}
|
||||
|
||||
private fun getSeekerSegmentsFromChapters(chapters: List<Chapter>, duration: Long) =
|
||||
chapters.map { chapter ->
|
||||
val markPosition = chapter.chapterStartInMs.toFloat() / duration.toFloat()
|
||||
if (markPosition < 0f || 1f < markPosition) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Chapter mark outside of stream duration range: chapter: ${chapter.chapterTitle}, mark in ms: ${chapter.chapterStartInMs}, vidoe duration in ms: ${duration}"
|
||||
)
|
||||
ChapterSegment(name = chapter.chapterTitle ?: "", start = 0f)
|
||||
} else {
|
||||
ChapterSegment(name = chapter.chapterTitle ?: "", start = markPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Preview
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -51,16 +51,14 @@ import net.newpipe.newplayer.R
|
|||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.playerInternals.PlaylistItem
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||
|
||||
@Composable
|
||||
fun TopUI(
|
||||
modifier: Modifier, viewModel: VideoPlayerViewModel, uiState: VideoPlayerUIState
|
||||
) {
|
||||
val embeddedUiConfig = getEmbeddedUiConfig(activity = LocalContext.current as Activity)
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
@ -101,7 +99,7 @@ fun TopUI(
|
|||
}
|
||||
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
||||
IconButton(
|
||||
onClick = { viewModel.openStreamSelection(selectChapter = true, embeddedUiConfig) },
|
||||
onClick = { viewModel.openStreamSelection(selectChapter = true) },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.MenuBook,
|
||||
|
@ -113,8 +111,7 @@ fun TopUI(
|
|||
IconButton(
|
||||
onClick = {
|
||||
viewModel.openStreamSelection(
|
||||
selectChapter = false,
|
||||
embeddedUiConfig
|
||||
selectChapter = false
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
package net.newpipe.newplayer.ui.videoplayer.gesture_ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.util.Log
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
@ -36,13 +35,11 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import net.newpipe.newplayer.model.VideoPlayerUIState
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||
import net.newpipe.newplayer.model.VideoPlayerViewModelDummy
|
||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||
|
||||
private const val TAG = "EmbeddedGestureUI"
|
||||
|
||||
|
@ -55,8 +52,6 @@ fun EmbeddedGestureUI(
|
|||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
val embeddedUiConfig = getEmbeddedUiConfig(LocalContext.current as Activity)
|
||||
|
||||
val handleMovement = { movement: TouchedPosition ->
|
||||
Log.d(TAG, "${movement.x}:${movement.y}")
|
||||
if (0 < movement.y) {
|
||||
|
@ -66,7 +61,7 @@ fun EmbeddedGestureUI(
|
|||
|
||||
// this check is there to allow a temporary move up in the downward gesture
|
||||
if (downwardMovementMode == false) {
|
||||
viewModel.switchToFullscreen(embeddedUiConfig)
|
||||
viewModel.switchToFullscreen()
|
||||
} else {
|
||||
viewModel.embeddedDraggedDown(movement.y)
|
||||
}
|
||||
|
|
|
@ -89,25 +89,6 @@ fun getLocale(): Locale? {
|
|||
return ConfigurationCompat.getLocales(configuration).get(0)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun getEmbeddedUiConfig(activity: Activity): EmbeddedUiConfig {
|
||||
val window = activity.window
|
||||
val view = LocalView.current
|
||||
|
||||
val isLightStatusBar = WindowCompat.getInsetsController(
|
||||
window,
|
||||
view
|
||||
).isAppearanceLightStatusBars
|
||||
val screenOrientation = activity.requestedOrientation
|
||||
val defaultBrightness = getDefaultBrightness(activity)
|
||||
return EmbeddedUiConfig(
|
||||
systemBarInLightMode = isLightStatusBar,
|
||||
brightness = defaultBrightness,
|
||||
screenOrientation = screenOrientation
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getInsets() =
|
||||
WindowInsets.systemBars.union(WindowInsets.displayCutout).union(WindowInsets.waterfall)
|
||||
|
|
Loading…
Reference in New Issue