make fit inside foo work

This commit is contained in:
Christian Schabesberger 2024-07-23 12:32:24 +02:00
parent 3903e89781
commit b26cf2b402
5 changed files with 79 additions and 60 deletions

View File

@ -4,6 +4,14 @@
<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">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=981f7af2" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

View File

@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.update
import net.newpipe.newplayer.utils.VideoSize 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.ContentFitMode import net.newpipe.newplayer.ui.ContentScale
val VIDEOPLAYER_UI_STATE = "video_player_ui_state" val VIDEOPLAYER_UI_STATE = "video_player_ui_state"
@ -51,7 +51,7 @@ data class VideoPlayerUIState(
var uiVisible: Boolean, var uiVisible: Boolean,
val contentRatio: Float, val contentRatio: Float,
val uiRatio: Float, val uiRatio: Float,
val contentFitMode: ContentFitMode val contentFitMode: ContentScale
) : Parcelable { ) : Parcelable {
companion object { companion object {
val DEFAULT = VideoPlayerUIState( val DEFAULT = VideoPlayerUIState(
@ -60,7 +60,7 @@ data class VideoPlayerUIState(
uiVisible = false, uiVisible = false,
contentRatio = 16 / 9F, contentRatio = 16 / 9F,
uiRatio = 16F / 9F, uiRatio = 16F / 9F,
contentFitMode = ContentFitMode.FIT_INSIDE contentFitMode = ContentScale.FIT_INSIDE
) )
} }
} }
@ -71,6 +71,7 @@ interface VideoPlayerViewModel {
val uiState: StateFlow<VideoPlayerUIState> val uiState: StateFlow<VideoPlayerUIState>
var minContentRatio: Float var minContentRatio: Float
var maxContentRatio: Float var maxContentRatio: Float
var contentFitMode: ContentScale
fun initUIState(instanceState: Bundle) fun initUIState(instanceState: Bundle)
fun play() fun play()
@ -129,6 +130,14 @@ class VideoPlayerViewModelImpl @Inject constructor(
} }
} }
override var contentFitMode: ContentScale
get() = mutableUiState.value.contentFitMode
set(value) {
mutableUiState.update {
it.copy(contentFitMode = value)
}
}
private fun installExoPlayer() { private fun installExoPlayer() {
player?.let { player -> player?.let { player ->
Log.d(TAG, "Install player: ${player.videoSize.width}") Log.d(TAG, "Install player: ${player.videoSize.width}")
@ -227,6 +236,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
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 fun initUIState(instanceState: Bundle) { override fun initUIState(instanceState: Bundle) {
println("dummy impl") println("dummy impl")

View File

@ -1,8 +1,8 @@
package net.newpipe.newplayer.ui package net.newpipe.newplayer.ui
enum class ContentFitMode { enum class ContentScale {
FILL, FILL,
FIT_INSIDE, FIT_INSIDE,
ZOOM CROP
} }

View File

@ -28,6 +28,8 @@ 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.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
@ -45,6 +47,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.media3.common.Player
import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModel
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
@ -107,60 +110,13 @@ fun VideoPlayerUI(
.aspectRatio(uiState.uiRatio), color = Color.Black .aspectRatio(uiState.uiRatio), color = Color.Black
) { ) {
Box(contentAlignment = Alignment.Center) { Box(contentAlignment = Alignment.Center) {
val viewBoxModifier = Modifier PlaySurface(
when (uiState.contentFitMode) { player = viewModel.player,
ContentFitMode.FILL -> { lifecycle = lifecycle,
println("fit mode fill") fitMode = uiState.contentFitMode,
viewBoxModifier.fillMaxSize() uiRatio = uiState.uiRatio,
} contentRatio = uiState.contentRatio
)
ContentFitMode.FIT_INSIDE -> {
println("fit mode fit inside:")
if (uiState.contentRatio < uiState.uiRatio) {
println("fit mode fill max height")
viewBoxModifier
.fillMaxHeight()
.aspectRatio(uiState.contentRatio)
} else if (uiState.uiRatio < uiState.contentRatio) {
println("fit mode fill max width")
viewBoxModifier
.fillMaxWidth()
.aspectRatio(uiState.contentRatio)
}
}
ContentFitMode.ZOOM -> {
println("fit mode zoom:")
if (uiState.uiRatio < uiState.contentRatio) {
viewBoxModifier
.fillMaxHeight()
.aspectRatio(uiState.contentRatio)
} else if (uiState.contentRatio < uiState.uiRatio) {
viewBoxModifier
.fillMaxWidth()
.aspectRatio(uiState.contentRatio)
}
}
}
Box(modifier = viewBoxModifier) {
AndroidView(factory = { context ->
SurfaceView(context).also { view ->
viewModel.player?.setVideoSurfaceView(view)
}
}, update = { view ->
when (lifecycle) {
Lifecycle.Event.ON_RESUME -> {
viewModel.player?.setVideoSurfaceView(view)
}
else -> Unit
}
})
Surface(color = Color.Green, modifier = Modifier.fillMaxSize()) {
}
}
} }
VideoPlayerControllerUI( VideoPlayerControllerUI(
isPlaying = uiState.playing, isPlaying = uiState.playing,
@ -176,6 +132,50 @@ fun VideoPlayerUI(
} }
} }
@Composable
fun PlaySurface(
player: Player?,
lifecycle: Lifecycle.Event,
fitMode: ContentScale,
uiRatio: Float,
contentRatio: Float
) {
val viewBoxModifier = Modifier
viewBoxModifier
.fillMaxWidth()
.aspectRatio(16F / 9F)
Box(
modifier = Modifier
.then(
when (fitMode) {
ContentScale.FILL -> Modifier.fillMaxSize()
ContentScale.FIT_INSIDE -> Modifier.aspectRatio(contentRatio)
ContentScale.CROP -> Modifier
.aspectRatio(contentRatio)
.wrapContentWidth(unbounded = true)
.fillMaxSize()
}
)
) {
AndroidView(factory = { context ->
SurfaceView(context).also { view ->
player?.setVideoSurfaceView(view)
}
}, update = { view ->
when (lifecycle) {
Lifecycle.Event.ON_RESUME -> {
player?.setVideoSurfaceView(view)
}
else -> Unit
}
})
}
}
@Preview(device = "spec:width=1080px,height=700px,dpi=440,orientation=landscape") @Preview(device = "spec:width=1080px,height=700px,dpi=440,orientation=landscape")
@Composable @Composable

View File

@ -26,12 +26,12 @@ 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.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.viewmodel.compose.viewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.NewPlayer
import net.newpipe.newplayer.VideoPlayerView import net.newpipe.newplayer.VideoPlayerView
import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModel
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
import net.newpipe.newplayer.ui.ContentScale
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -52,6 +52,7 @@ class MainActivity : AppCompatActivity() {
videoPlayerViewModel.newPlayer = newPlayer videoPlayerViewModel.newPlayer = newPlayer
videoPlayerViewModel.maxContentRatio = 4F/3F videoPlayerViewModel.maxContentRatio = 4F/3F
videoPlayerViewModel.contentFitMode = ContentScale.FIT_INSIDE
/* /*
video_view.fullScreenToggleListener = object : VideoPlayerView.FullScreenToggleListener { video_view.fullScreenToggleListener = object : VideoPlayerView.FullScreenToggleListener {