commit shit

This commit is contained in:
Christian Schabesberger 2024-07-23 16:58:33 +02:00
parent 8551a36a0c
commit b95db7cd07
5 changed files with 100 additions and 55 deletions

View File

@ -4,7 +4,7 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="TestApp"> <SelectionState runConfigName="TestApp">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-07-23T10:30:52.346401525Z"> <DropdownSelection timestamp="2024-07-23T14:30:02.857797708Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=981f7af2" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=981f7af2" />

View File

@ -29,7 +29,6 @@ import androidx.annotation.RequiresApi
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.media3.common.Player import androidx.media3.common.Player
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -44,7 +43,6 @@ import net.newpipe.newplayer.utils.VideoSize
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.NewPlayer
import net.newpipe.newplayer.ui.ContentScale import net.newpipe.newplayer.ui.ContentScale
import java.lang.Thread.sleep
val VIDEOPLAYER_UI_STATE = "video_player_ui_state" val VIDEOPLAYER_UI_STATE = "video_player_ui_state"
@ -57,7 +55,7 @@ data class VideoPlayerUIState(
val uiVissible: Boolean, val uiVissible: Boolean,
var uiVisible: Boolean, var uiVisible: Boolean,
val contentRatio: Float, val contentRatio: Float,
val uiRatio: Float, val embeddedUiRatio: Float,
val contentFitMode: ContentScale val contentFitMode: ContentScale
) : Parcelable { ) : Parcelable {
companion object { companion object {
@ -67,7 +65,7 @@ data class VideoPlayerUIState(
uiVissible = false, uiVissible = false,
uiVisible = false, uiVisible = false,
contentRatio = 16 / 9F, contentRatio = 16 / 9F,
uiRatio = 16F / 9F, embeddedUiRatio = 16F / 9F,
contentFitMode = ContentScale.FIT_INSIDE contentFitMode = ContentScale.FIT_INSIDE
) )
} }
@ -80,7 +78,7 @@ interface VideoPlayerViewModel {
var minContentRatio: Float var minContentRatio: Float
var maxContentRatio: Float var maxContentRatio: Float
var contentFitMode: ContentScale var contentFitMode: ContentScale
var fullscreenListener: FullscreenListener? var callbackListener: Listener?
fun initUIState(instanceState: Bundle) fun initUIState(instanceState: Bundle)
fun play() fun play()
@ -92,8 +90,9 @@ interface VideoPlayerViewModel {
fun showUi() fun showUi()
fun hideUi() fun hideUi()
interface FullscreenListener { interface Listener {
fun onFullscreenToggle(isFullscreen: Boolean) fun onFullscreenToggle(isFullscreen: Boolean)
fun onUiVissibleToggle(isVissible: Boolean)
} }
} }
@ -106,10 +105,10 @@ class VideoPlayerViewModelImpl @Inject constructor(
// private // private
private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
private var currentContentRatio = 1F private var currentContentRatio = 1F
private var uiVisibilityJob:Job? = null private var uiVisibilityJob: Job? = null
//interface //interface
override var fullscreenListener: VideoPlayerViewModel.FullscreenListener? = null override var callbackListener: VideoPlayerViewModel.Listener? = null
override var newPlayer: NewPlayer? = null override var newPlayer: NewPlayer? = null
set(value) { set(value) {
@ -131,7 +130,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
) )
else { else {
field = value field = value
mutableUiState.update { it.copy(uiRatio = getUiRatio()) } mutableUiState.update { it.copy(embeddedUiRatio = getEmbeddedUiRatio()) }
} }
} }
@ -145,7 +144,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
) )
else { else {
field = value field = value
mutableUiState.update { it.copy(uiRatio = getUiRatio()) } mutableUiState.update { it.copy(embeddedUiRatio = getEmbeddedUiRatio()) }
} }
} }
@ -186,7 +185,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
mutableUiState.update { mutableUiState.update {
it.copy( it.copy(
contentRatio = currentContentRatio, contentRatio = currentContentRatio,
uiRatio = getUiRatio() embeddedUiRatio = getEmbeddedUiRatio()
) )
} }
} }
@ -214,15 +213,12 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
override fun play() { override fun play() {
uiVisibilityJob?.cancel() hideUi()
mutableUiState.update {
it.copy(uiVissible = false)
}
newPlayer?.play() newPlayer?.play()
} }
override fun pause() { override fun pause() {
resetHideUiDelayed() uiVisibilityJob?.cancel()
newPlayer?.pause() newPlayer?.pause()
} }
@ -237,6 +233,9 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
override fun showUi() { override fun showUi() {
if (mutableUiState.value.fullscreen)
callbackListener?.onUiVissibleToggle(true)
mutableUiState.update { mutableUiState.update {
it.copy(uiVissible = true) it.copy(uiVissible = true)
} }
@ -246,14 +245,15 @@ class VideoPlayerViewModelImpl @Inject constructor(
private fun resetHideUiDelayed() { private fun resetHideUiDelayed() {
uiVisibilityJob?.cancel() uiVisibilityJob?.cancel()
uiVisibilityJob = viewModelScope.launch { uiVisibilityJob = viewModelScope.launch {
delay(2000) delay(4000)
mutableUiState.update { hideUi()
it.copy(uiVissible = false)
}
} }
} }
override fun hideUi() { override fun hideUi() {
if (mutableUiState.value.fullscreen)
callbackListener?.onUiVissibleToggle(false)
uiVisibilityJob?.cancel() uiVisibilityJob?.cancel()
mutableUiState.update { mutableUiState.update {
it.copy(uiVissible = false) it.copy(uiVissible = false)
@ -261,7 +261,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
override fun switchToEmbeddedView() { override fun switchToEmbeddedView() {
fullscreenListener?.onFullscreenToggle(false) callbackListener?.onFullscreenToggle(false)
uiVisibilityJob?.cancel() uiVisibilityJob?.cancel()
mutableUiState.update { mutableUiState.update {
it.copy(fullscreen = false, uiVissible = false) it.copy(fullscreen = false, uiVissible = false)
@ -269,7 +269,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
override fun switchToFullscreen() { override fun switchToFullscreen() {
fullscreenListener?.onFullscreenToggle(true) callbackListener?.onFullscreenToggle(true)
uiVisibilityJob?.cancel() uiVisibilityJob?.cancel()
mutableUiState.update { mutableUiState.update {
@ -277,13 +277,15 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
} }
private fun getUiRatio() = private fun getEmbeddedUiRatio() =
player?.let { player -> player?.let { player ->
val videoRatio = VideoSize.fromMedia3VideoSize(player.videoSize).getRatio() val videoRatio = VideoSize.fromMedia3VideoSize(player.videoSize).getRatio()
return if (videoRatio.isNaN()) return (if (videoRatio.isNaN())
minContentRatio currentContentRatio
else else
videoRatio.coerceIn(minContentRatio, maxContentRatio) videoRatio).coerceIn(minContentRatio, maxContentRatio)
} ?: minContentRatio } ?: minContentRatio
@ -295,7 +297,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
override var minContentRatio = 4F / 3F override var minContentRatio = 4F / 3F
override var maxContentRatio = 16F / 9F override var maxContentRatio = 16F / 9F
override var contentFitMode = ContentScale.FIT_INSIDE override var contentFitMode = ContentScale.FIT_INSIDE
override var fullscreenListener: VideoPlayerViewModel.FullscreenListener? = null override var callbackListener: VideoPlayerViewModel.Listener? = null
override fun initUIState(instanceState: Bundle) { override fun initUIState(instanceState: Bundle) {
println("dummy impl") println("dummy impl")

View File

@ -29,14 +29,19 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.defaultMinSize
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.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.windowInsetsBottomHeight
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.windowInsetsTopHeight
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.automirrored.filled.MenuBook import androidx.compose.material.icons.automirrored.filled.MenuBook
@ -100,7 +105,15 @@ fun VideoPlayerControllerUI(
hideUi: () -> Unit hideUi: () -> Unit
) { ) {
Box(modifier = Modifier) { val insets = WindowInsets.systemBars
Box(
modifier = Modifier.then(
if (fullscreen)
Modifier.windowInsetsPadding(insets)
else
Modifier
)
) {
if (!uiVissible) { if (!uiVissible) {
TouchUi( TouchUi(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
@ -124,7 +137,6 @@ fun VideoPlayerControllerUI(
modifier = if (fullscreen) { modifier = if (fullscreen) {
Modifier Modifier
.background(Color.Transparent) .background(Color.Transparent)
.windowInsetsPadding(WindowInsets.systemBars)
} else { } else {
Modifier Modifier
.background(Color.Transparent) .background(Color.Transparent)

View File

@ -22,18 +22,15 @@ package net.newpipe.newplayer.ui
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.view.SurfaceView import android.view.SurfaceView
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio 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.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
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
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -42,6 +39,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
@ -60,7 +58,7 @@ fun VideoPlayerUI(
if (viewModel == null) { if (viewModel == null) {
VideoPlayerLoadingPlaceholder() VideoPlayerLoadingPlaceholder()
} else if (viewModel.player == null) { } else if (viewModel.player == null) {
VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.uiRatio) VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.embeddedUiRatio)
} else { } else {
val uiState by viewModel.uiState.collectAsState() val uiState by viewModel.uiState.collectAsState()
@ -68,6 +66,8 @@ fun VideoPlayerUI(
mutableStateOf(Lifecycle.Event.ON_CREATE) mutableStateOf(Lifecycle.Event.ON_CREATE)
} }
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current val lifecycleOwner = LocalLifecycleOwner.current
// Prepare stuff for the SurfaceView to which the video will be rendered // Prepare stuff for the SurfaceView to which the video will be rendered
@ -83,17 +83,6 @@ fun VideoPlayerUI(
} }
// Handle Fullscreen/Embedded view transition
if (uiState.fullscreen) {
BackHandler {
//closeFullscreen(viewModel, activity!!)
}
}
LaunchedEffect(key1 = uiState.fullscreen) {
println("gurken launch fullscreen: ${uiState.fullscreen}")
}
// Set Screen Rotation // Set Screen Rotation
if (uiState.fullscreen) { if (uiState.fullscreen) {
if (uiState.contentRatio < 1) { if (uiState.contentRatio < 1) {
@ -103,18 +92,22 @@ fun VideoPlayerUI(
} }
} }
val displayMetrics = context.resources.displayMetrics
val screenRatio =
displayMetrics.widthPixels.toFloat() / displayMetrics.heightPixels.toFloat()
// Set UI // Set UI
Surface( Surface(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.aspectRatio(uiState.uiRatio), color = Color.Black .aspectRatio(uiState.embeddedUiRatio), color = Color.Black
) { ) {
Box(contentAlignment = Alignment.Center) { Box(contentAlignment = Alignment.Center) {
PlaySurface( PlaySurface(
player = viewModel.player, player = viewModel.player,
lifecycle = lifecycle, lifecycle = lifecycle,
fitMode = uiState.contentFitMode, fitMode = uiState.contentFitMode,
uiRatio = uiState.uiRatio, uiRatio = if (uiState.fullscreen) screenRatio else uiState.embeddedUiRatio,
contentRatio = uiState.contentRatio contentRatio = uiState.contentRatio
) )
} }
@ -148,12 +141,19 @@ fun PlaySurface(
.fillMaxWidth() .fillMaxWidth()
.aspectRatio(16F / 9F) .aspectRatio(16F / 9F)
/*
Box( Box(
modifier = Modifier modifier = Modifier
.then( .then(
when (fitMode) { when (fitMode) {
ContentScale.FILL -> Modifier.fillMaxSize() ContentScale.FILL -> Modifier.fillMaxSize()
ContentScale.FIT_INSIDE -> Modifier.aspectRatio(contentRatio) ContentScale.FIT_INSIDE -> Modifier
.aspectRatio(contentRatio)
.then(
if (contentRatio < uiRatio) Modifier
.fillMaxWidth() else Modifier.fillMaxHeight()
)
ContentScale.CROP -> Modifier ContentScale.CROP -> Modifier
.aspectRatio(contentRatio) .aspectRatio(contentRatio)
.wrapContentWidth(unbounded = true) .wrapContentWidth(unbounded = true)
@ -161,7 +161,8 @@ fun PlaySurface(
} }
) )
) { ) {
*/
Box(modifier = Modifier.fillMaxHeight().aspectRatio(contentRatio)) {
AndroidView(factory = { context -> AndroidView(factory = { context ->
SurfaceView(context).also { view -> SurfaceView(context).also { view ->
player?.setVideoSurfaceView(view) player?.setVideoSurfaceView(view)

View File

@ -27,6 +27,7 @@ import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -62,17 +63,33 @@ class MainActivity : AppCompatActivity() {
video_view.viewModel = videoPlayerViewModel video_view.viewModel = videoPlayerViewModel
videoPlayerViewModel.newPlayer = newPlayer videoPlayerViewModel.newPlayer = newPlayer
//videoPlayerViewModel.maxContentRatio = 4F/3F videoPlayerViewModel.maxContentRatio = 4F/3F
videoPlayerViewModel.contentFitMode = ContentScale.FIT_INSIDE videoPlayerViewModel.contentFitMode = ContentScale.FIT_INSIDE
if (videoPlayerViewModel.uiState.value.fullscreen) { val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(0, 0, 0, 0) v.setPadding(
systemBars.left,
systemBars.top,
systemBars.right,
systemBars.bottom
)
insets insets
} }
if (videoPlayerViewModel.uiState.value.fullscreen) {
//ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
// v.setPadding(0, 0, 0, 0)
// insets
//}
buttons_layout.visibility = View.GONE buttons_layout.visibility = View.GONE
//windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
} else { } else {
buttons_layout.visibility = View.VISIBLE buttons_layout.visibility = View.VISIBLE
@ -86,8 +103,21 @@ class MainActivity : AppCompatActivity() {
) )
insets insets
} }
//windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
} }
videoPlayerViewModel.callbackListener = object : VideoPlayerViewModel.Listener {
override fun onFullscreenToggle(isFullscreen: Boolean) {}
override fun onUiVissibleToggle(isVissible: Boolean) {
if (isVissible) {
// windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
} else {
// windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
}
}
}
} }
} }