make progress update more smooth
This commit is contained in:
parent
642e5e78db
commit
f750fa8b4b
|
@ -38,6 +38,7 @@ interface NewPlayerViewModel {
|
|||
var contentFitMode: ContentScale
|
||||
val embeddedPlayerDraggedDownBy: SharedFlow<Float>
|
||||
val onBackPressed: SharedFlow<Unit>
|
||||
var deviceInPowerSaveMode: Boolean
|
||||
|
||||
fun initUIState(instanceState: Bundle)
|
||||
fun play()
|
||||
|
|
|
@ -18,6 +18,7 @@ open class NewPlayerViewModelDummy : NewPlayerViewModel {
|
|||
override var contentFitMode = ContentScale.FIT_INSIDE
|
||||
override val embeddedPlayerDraggedDownBy = MutableSharedFlow<Float>().asSharedFlow()
|
||||
override val onBackPressed: SharedFlow<Unit> = MutableSharedFlow<Unit>().asSharedFlow()
|
||||
override var deviceInPowerSaveMode: Boolean = false
|
||||
|
||||
override fun initUIState(instanceState: Bundle) {
|
||||
println("dummy impl")
|
||||
|
|
|
@ -49,6 +49,7 @@ import net.newpipe.newplayer.NewPlayer
|
|||
import net.newpipe.newplayer.NewPlayerException
|
||||
import net.newpipe.newplayer.RepeatMode
|
||||
import net.newpipe.newplayer.ui.ContentScale
|
||||
import net.newpipe.newplayer.utils.isInPowerSaveMode
|
||||
import java.util.LinkedList
|
||||
|
||||
val VIDEOPLAYER_UI_STATE = "video_player_ui_state"
|
||||
|
@ -136,6 +137,15 @@ class NewPlayerViewModelImpl @Inject constructor(
|
|||
private var mutableOnBackPressed = MutableSharedFlow<Unit>()
|
||||
override val onBackPressed: SharedFlow<Unit> = mutableOnBackPressed.asSharedFlow()
|
||||
|
||||
override var deviceInPowerSaveMode: Boolean = false
|
||||
get() = field
|
||||
set(value) {
|
||||
field = value
|
||||
if (progressUpdaterJob?.isActive == true) {
|
||||
resetProgressUpdatePeriodicallyJob()
|
||||
}
|
||||
}
|
||||
|
||||
private fun installNewPlayer() {
|
||||
newPlayer?.let { newPlayer ->
|
||||
viewModelScope.launch {
|
||||
|
@ -334,8 +344,9 @@ class NewPlayerViewModelImpl @Inject constructor(
|
|||
this.embeddedUiConfig = embeddedUiConfig
|
||||
}
|
||||
|
||||
if(!(newUiModeState == UIModeState.EMBEDDED_VIDEO_CONTROLLER_UI ||
|
||||
newUiModeState == UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI)) {
|
||||
if (!(newUiModeState == UIModeState.EMBEDDED_VIDEO_CONTROLLER_UI ||
|
||||
newUiModeState == UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI)
|
||||
) {
|
||||
uiVisibilityJob?.cancel()
|
||||
} else {
|
||||
resetHideUiDelayedJob()
|
||||
|
@ -368,10 +379,10 @@ class NewPlayerViewModelImpl @Inject constructor(
|
|||
}
|
||||
|
||||
private fun resetHideUiDelayedJob() {
|
||||
var ex:Exception? = null
|
||||
var ex: Exception? = null
|
||||
try {
|
||||
throw Exception()
|
||||
} catch(e: Exception) {
|
||||
} catch (e: Exception) {
|
||||
ex = e
|
||||
}
|
||||
uiVisibilityJob?.cancel()
|
||||
|
@ -387,7 +398,7 @@ class NewPlayerViewModelImpl @Inject constructor(
|
|||
progressUpdaterJob = viewModelScope.launch {
|
||||
while (true) {
|
||||
updateProgressOnce()
|
||||
delay(1000)
|
||||
delay(if (deviceInPowerSaveMode) 1000 else 1000 / 30/*fps*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package net.newpipe.newplayer.ui
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.SurfaceView
|
||||
import androidx.activity.compose.BackHandler
|
||||
|
@ -54,6 +55,7 @@ import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
|||
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerUi
|
||||
import net.newpipe.newplayer.utils.LockScreenOrientation
|
||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||
import net.newpipe.newplayer.utils.isInPowerSaveMode
|
||||
import net.newpipe.newplayer.utils.setScreenBrightness
|
||||
|
||||
private const val TAG = "VideoPlayerUI"
|
||||
|
@ -112,6 +114,13 @@ fun NewPlayerUI(
|
|||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val isInPowerSaveMode = isInPowerSaveMode()
|
||||
LaunchedEffect(key1 = isInPowerSaveMode) {
|
||||
viewModel.deviceInPowerSaveMode = isInPowerSaveMode
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.uiMode.fitScreenRotation) {
|
||||
if (uiState.contentRatio < 1) {
|
||||
LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
|
@ -59,6 +60,8 @@ import net.newpipe.newplayer.ui.selection_ui.StreamSelectUI
|
|||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||
import net.newpipe.newplayer.utils.Thumbnail
|
||||
import net.newpipe.newplayer.utils.getInsets
|
||||
import net.newpipe.newplayer.utils.getLocale
|
||||
import net.newpipe.newplayer.utils.getTimeStringFromMs
|
||||
|
||||
|
||||
private val UI_ENTER_ANIMATION = fadeIn(tween(200))
|
||||
|
@ -75,6 +78,9 @@ fun lightAudioControlButtonColorScheme() = ButtonDefaults.buttonColors().copy(
|
|||
@Composable
|
||||
fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||
val insets = getInsets()
|
||||
|
||||
val locale = getLocale()!!
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
@ -164,7 +170,25 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
|||
.fillMaxSize()
|
||||
.weight(0.2f)
|
||||
)
|
||||
|
||||
NewPlayerSeeker(viewModel = viewModel, uiState = uiState)
|
||||
|
||||
Row() {
|
||||
Text(
|
||||
getTimeStringFromMs(
|
||||
uiState.playbackPositionInMs,
|
||||
getLocale() ?: locale
|
||||
)
|
||||
)
|
||||
Box(modifier = Modifier.fillMaxWidth().weight(1f))
|
||||
Text(
|
||||
getTimeStringFromMs(
|
||||
uiState.durationInMs,
|
||||
getLocale() ?: locale
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
@ -195,6 +219,9 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
|||
@Composable
|
||||
fun AudioPlayerUIPreview() {
|
||||
VideoPlayerTheme {
|
||||
AudioPlayerUI(viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY)
|
||||
AudioPlayerUI(
|
||||
viewModel = NewPlayerViewModelDummy(),
|
||||
uiState = NewPlayerUIState.DUMMY.copy(uiMode = UIModeState.FULLSCREEN_AUDIO)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -23,7 +23,9 @@ package net.newpipe.newplayer.ui.videoplayer.controller
|
|||
import android.app.Activity
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Fullscreen
|
||||
import androidx.compose.material.icons.filled.FullscreenExit
|
||||
|
@ -38,6 +40,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import net.newpipe.newplayer.R
|
||||
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
||||
|
@ -67,7 +70,13 @@ fun BottomUI(
|
|||
val locale = getLocale()!!
|
||||
Text(getTimeStringFromMs(uiState.playbackPositionInMs, getLocale() ?: locale))
|
||||
|
||||
NewPlayerSeeker(modifier = Modifier.weight(1F), viewModel = viewModel, uiState = uiState)
|
||||
NewPlayerSeeker(
|
||||
modifier = Modifier
|
||||
.weight(1F)
|
||||
.padding(start = 4.dp, end = 4.dp),
|
||||
viewModel = viewModel,
|
||||
uiState = uiState
|
||||
)
|
||||
|
||||
Text(getTimeStringFromMs(uiState.durationInMs, getLocale() ?: locale))
|
||||
|
||||
|
@ -112,7 +121,7 @@ fun VideoPlayerControllerBottomUIPreview() {
|
|||
viewModel = NewPlayerViewModelDummy(),
|
||||
uiState = NewPlayerUIState.DUMMY.copy(
|
||||
uiMode = UIModeState.FULLSCREEN_VIDEO_CONTROLLER_UI,
|
||||
seekerPosition = 0.2f,
|
||||
seekerPosition = 0.0f,
|
||||
playbackPositionInMs = 3 * 60 * 1000,
|
||||
bufferedPercentage = 0.4f
|
||||
),
|
||||
|
|
|
@ -24,25 +24,23 @@ import android.annotation.SuppressLint
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.graphics.drawable.shapes.Shape
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.compose.animation.core.withInfiniteAnimationFrameMillis
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.waterfall
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
|
@ -184,6 +182,13 @@ fun Thumbnail(
|
|||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Composable
|
||||
fun isInPowerSaveMode() =
|
||||
(LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager)
|
||||
.isPowerSaveMode
|
||||
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun getPlaylistDurationInMS(playlist: List<MediaItem>) : Long {
|
||||
var duration = 0L
|
||||
|
|
Loading…
Reference in New Issue