make fit inside foo work
This commit is contained in:
parent
3903e89781
commit
b26cf2b402
|
@ -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>
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue