show buffered percentage and fix progressbar colors

This commit is contained in:
Christian Schabesberger 2024-07-29 18:31:32 +02:00
parent 51b85c1720
commit 9786a5634d
8 changed files with 48 additions and 14 deletions

View File

@ -34,6 +34,7 @@ data class VideoPlayerUIState(
val embeddedUiRatio: Float, val embeddedUiRatio: Float,
val contentFitMode: ContentScale, val contentFitMode: ContentScale,
val seekerPosition: Float, val seekerPosition: Float,
val bufferedPercentage: Float,
val isLoading: Boolean, val isLoading: Boolean,
val durationInMs: Long, val durationInMs: Long,
val playbackPositionInMs: Long val playbackPositionInMs: Long
@ -44,10 +45,11 @@ data class VideoPlayerUIState(
fullscreen = false, fullscreen = false,
uiVissible = false, uiVissible = false,
uiVisible = false, uiVisible = false,
contentRatio = 16 / 9F, contentRatio = 16 / 9f,
embeddedUiRatio = 16F / 9F, embeddedUiRatio = 16f / 9f,
contentFitMode = ContentScale.FIT_INSIDE, contentFitMode = ContentScale.FIT_INSIDE,
seekerPosition = 0F, seekerPosition = 0f,
bufferedPercentage = 0f,
isLoading = true, isLoading = true,
durationInMs = 0, durationInMs = 0,
playbackPositionInMs = 0 playbackPositionInMs = 0

View File

@ -34,7 +34,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -230,12 +229,15 @@ class VideoPlayerViewModelImpl @Inject constructor(
private fun updateProgressOnce() { private fun updateProgressOnce() {
val progress = player?.currentPosition ?: 0 val progress = player?.currentPosition ?: 0
val duration = player?.duration ?: 1 val duration = player?.duration ?: 1
val bufferedPercentage = (player?.bufferedPercentage?.toFloat() ?: 0f) / 100f
val progressPercentage = progress.toFloat() / duration.toFloat() val progressPercentage = progress.toFloat() / duration.toFloat()
mutableUiState.update { mutableUiState.update {
it.copy( it.copy(
seekerPosition = progressPercentage, seekerPosition = progressPercentage,
durationInMs = duration, durationInMs = duration,
playbackPositionInMs = progress playbackPositionInMs = progress,
bufferedPercentage = bufferedPercentage
) )
} }
} }

View File

@ -61,6 +61,7 @@ fun VideoPlayerControllerUI(
isLoading: Boolean, isLoading: Boolean,
durationInMs: Long, durationInMs: Long,
playbackPositionInMs: Long, playbackPositionInMs: Long,
bufferedPercentage: Float,
play: () -> Unit, play: () -> Unit,
pause: () -> Unit, pause: () -> Unit,
prevStream: () -> Unit, prevStream: () -> Unit,
@ -158,6 +159,7 @@ fun VideoPlayerControllerUI(
durationInMs = durationInMs, durationInMs = durationInMs,
playbackPositionInMs = playbackPositionInMs, playbackPositionInMs = playbackPositionInMs,
seekPosition = seekPosition, seekPosition = seekPosition,
bufferedPercentage = bufferedPercentage,
switchToFullscreen = switchToFullscreen, switchToFullscreen = switchToFullscreen,
switchToEmbeddedView = switchToEmbeddedView, switchToEmbeddedView = switchToEmbeddedView,
seekPositionChanged = seekPositionChanged, seekPositionChanged = seekPositionChanged,
@ -203,6 +205,7 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
isLoading = false, isLoading = false,
durationInMs = 9*60*1000, durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000, playbackPositionInMs = 6*60*1000,
bufferedPercentage = 0.4f,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},
@ -229,6 +232,7 @@ fun VideoPlayerControllerUIPreviewLandscape() {
isLoading = true, isLoading = true,
durationInMs = 9*60*1000, durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000, playbackPositionInMs = 6*60*1000,
bufferedPercentage = 0.4f,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},
@ -256,6 +260,7 @@ fun VideoPlayerControllerUIPreviewPortrait() {
isLoading = false, isLoading = false,
durationInMs = 9*60*1000, durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000, playbackPositionInMs = 6*60*1000,
bufferedPercentage = 0.4f,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},

View File

@ -28,7 +28,6 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
@ -152,6 +151,7 @@ fun VideoPlayerUI(
isLoading = uiState.isLoading, isLoading = uiState.isLoading,
durationInMs = uiState.durationInMs, durationInMs = uiState.durationInMs,
playbackPositionInMs = uiState.playbackPositionInMs, playbackPositionInMs = uiState.playbackPositionInMs,
bufferedPercentage = uiState.bufferedPercentage,
play = viewModel::play, play = viewModel::play,
pause = viewModel::pause, pause = viewModel::pause,
prevStream = viewModel::prevStream, prevStream = viewModel::prevStream,

View File

@ -21,6 +21,7 @@
*/ */
package net.newpipe.newplayer.ui.seeker package net.newpipe.newplayer.ui.seeker
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
@ -49,16 +50,16 @@ object SeekerDefaults {
*/ */
@Composable @Composable
fun seekerColors( fun seekerColors(
progressColor: Color = VideoPlayerColorScheme.primary, progressColor: Color = MaterialTheme.colorScheme.primary,
trackColor: Color = TrackColor, trackColor: Color = TrackColor,
disabledProgressColor: Color = VideoPlayerColorScheme.onSurface.copy(alpha = DisabledProgressAlpha), disabledProgressColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = DisabledProgressAlpha),
disabledTrackColor: Color = disabledProgressColor disabledTrackColor: Color = disabledProgressColor
.copy(alpha = DisabledTrackAlpha) .copy(alpha = DisabledTrackAlpha)
.compositeOver(VideoPlayerColorScheme.onSurface), .compositeOver(MaterialTheme.colorScheme.onSurface),
thumbColor: Color = VideoPlayerColorScheme.primary, thumbColor: Color = MaterialTheme.colorScheme.primary,
disabledThumbColor: Color = VideoPlayerColorScheme.onSurface disabledThumbColor: Color = MaterialTheme.colorScheme.onSurface
.copy(alpha = 0.0F) .copy(alpha = 0.0F)
.compositeOver(VideoPlayerColorScheme.surface), .compositeOver(MaterialTheme.colorScheme.surface),
readAheadColor: Color = ReadAheadColor readAheadColor: Color = ReadAheadColor
): SeekerColors = DefaultSeekerColor( ): SeekerColors = DefaultSeekerColor(
progressColor = progressColor, progressColor = progressColor,

View File

@ -58,7 +58,9 @@ val video_player_onSurface = Color(0xFFF8F8F8)
// The color of the menu Icons // The color of the menu Icons
val video_player_onSurfaceVariant = Color(0xFFF8F8F8) val video_player_onSurfaceVariant = Color(0xFFF8F8F8)
// The background color of the seekbar
val video_player_surfaceVariant = Color(0xFF4F4539) val video_player_surfaceVariant = Color(0xFF4F4539)
val video_player_outline = Color(0xFF9C8F80) val video_player_outline = Color(0xFF9C8F80)
val video_player_inverseOnSurface = Color(0xFF1F1B16) val video_player_inverseOnSurface = Color(0xFF1F1B16)
val video_player_inverseSurface = Color(0xFFEAE1D9) val video_player_inverseSurface = Color(0xFFEAE1D9)
@ -80,6 +82,7 @@ fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() {
isLoading = false, isLoading = false,
durationInMs = 9*60*1000, durationInMs = 9*60*1000,
playbackPositionInMs = 6*60*1000, playbackPositionInMs = 6*60*1000,
bufferedPercentage = 0.4f,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},

View File

@ -29,6 +29,7 @@ import androidx.compose.material.icons.filled.Fullscreen
import androidx.compose.material.icons.filled.FullscreenExit import androidx.compose.material.icons.filled.FullscreenExit
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -41,7 +42,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import net.newpipe.newplayer.R import net.newpipe.newplayer.R
import net.newpipe.newplayer.ui.seeker.DefaultSeekerColor
import net.newpipe.newplayer.ui.seeker.Seeker 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.theme.VideoPlayerTheme import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
import java.util.Locale import java.util.Locale
import kotlin.math.min import kotlin.math.min
@ -53,6 +57,7 @@ fun BottomUI(
seekPosition: Float, seekPosition: Float,
durationInMs: Long, durationInMs: Long,
playbackPositionInMs: Long, playbackPositionInMs: Long,
bufferedPercentage: Float,
switchToFullscreen: () -> Unit, switchToFullscreen: () -> Unit,
switchToEmbeddedView: () -> Unit, switchToEmbeddedView: () -> Unit,
seekPositionChanged: (Float) -> Unit, seekPositionChanged: (Float) -> Unit,
@ -68,7 +73,9 @@ fun BottomUI(
Modifier.weight(1F), Modifier.weight(1F),
value = seekPosition, value = seekPosition,
onValueChange = seekPositionChanged, onValueChange = seekPositionChanged,
onValueChangeFinished = seekingFinished onValueChangeFinished = seekingFinished,
readAheadValue = bufferedPercentage,
colors = customizedSeekerColors()
) )
//Slider(value = 0.4F, onValueChange = {}, modifier = Modifier.weight(1F)) //Slider(value = 0.4F, onValueChange = {}, modifier = Modifier.weight(1F))
@ -85,6 +92,20 @@ fun BottomUI(
} }
} }
@Composable
private fun customizedSeekerColors() : SeekerColors {
val colors = DefaultSeekerColor(
progressColor = MaterialTheme.colorScheme.primary,
thumbColor = MaterialTheme.colorScheme.primary,
trackColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.7f),
readAheadColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f),
disabledProgressColor = MaterialTheme.colorScheme.primary,
disabledThumbColor = MaterialTheme.colorScheme.primary,
disabledTrackColor = MaterialTheme.colorScheme.primary
)
return colors
}
@Composable @Composable
@ReadOnlyComposable @ReadOnlyComposable
fun getLocale(): Locale? { fun getLocale(): Locale? {
@ -136,6 +157,7 @@ fun VideoPlayerControllerBottomUIPreview() {
seekPosition = 0.4F, seekPosition = 0.4F,
durationInMs = 90 * 60 * 1000, durationInMs = 90 * 60 * 1000,
playbackPositionInMs = 3 * 60 * 1000, playbackPositionInMs = 3 * 60 * 1000,
bufferedPercentage = 0.4f,
switchToFullscreen = { }, switchToFullscreen = { },
switchToEmbeddedView = { }, switchToEmbeddedView = { },
seekPositionChanged = {} seekPositionChanged = {}

View File

@ -22,6 +22,5 @@
<resources> <resources>
<string name="ccc_6502_video" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2010/mp4-h264-HQ/27c3-4159-en-reverse_engineering_mos_6502.mp4</string> <string name="ccc_6502_video" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2010/mp4-h264-HQ/27c3-4159-en-reverse_engineering_mos_6502.mp4</string>
<string name="ccc_6502_audio" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2010/ogg-audio-only/27c3-4159-en-reverse_engineering_mos_6502.ogg</string> <string name="ccc_6502_audio" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2010/ogg-audio-only/27c3-4159-en-reverse_engineering_mos_6502.ogg</string>
<string name="ccc_chromebooks_video" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2023/h264-hd/37c3-11929-eng-deu-swe-Turning_Chromebooks_into_regular_laptops_hd.mp4</string>
<string name="portrait_video_example" translatable="false">https://videos.pexels.com/video-files/5512609/5512609-hd_1080_1920_25fps.mp4</string> <string name="portrait_video_example" translatable="false">https://videos.pexels.com/video-files/5512609/5512609-hd_1080_1920_25fps.mp4</string>
</resources> </resources>