add touchable surface

This commit is contained in:
Christian Schabesberger 2024-07-23 14:09:11 +02:00
parent b5b75558b5
commit 5a2f62b55e
3 changed files with 123 additions and 44 deletions

View File

@ -28,17 +28,23 @@ import android.util.Log
import androidx.annotation.RequiresApi 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.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.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.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 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.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"
@ -48,6 +54,7 @@ private const val TAG = "VideoPlayerViewModel"
data class VideoPlayerUIState( data class VideoPlayerUIState(
val playing: Boolean, val playing: Boolean,
var fullscreen: Boolean, var fullscreen: Boolean,
val uiVissible: Boolean,
var uiVisible: Boolean, var uiVisible: Boolean,
val contentRatio: Float, val contentRatio: Float,
val uiRatio: Float, val uiRatio: Float,
@ -57,6 +64,7 @@ data class VideoPlayerUIState(
val DEFAULT = VideoPlayerUIState( val DEFAULT = VideoPlayerUIState(
playing = false, playing = false,
fullscreen = false, fullscreen = false,
uiVissible = false,
uiVisible = false, uiVisible = false,
contentRatio = 16 / 9F, contentRatio = 16 / 9F,
uiRatio = 16F / 9F, uiRatio = 16F / 9F,
@ -81,6 +89,8 @@ interface VideoPlayerViewModel {
fun nextStream() fun nextStream()
fun switchToFullscreen() fun switchToFullscreen()
fun switchToEmbeddedView() fun switchToEmbeddedView()
fun showUi()
fun hideUi()
interface FullscreenListener { interface FullscreenListener {
fun onFullscreenToggle(isFullscreen: Boolean) fun onFullscreenToggle(isFullscreen: Boolean)
@ -96,6 +106,7 @@ 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
//interface //interface
override var fullscreenListener: VideoPlayerViewModel.FullscreenListener? = null override var fullscreenListener: VideoPlayerViewModel.FullscreenListener? = null
@ -169,7 +180,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
fun updateContentRatio(videoSize: VideoSize) { fun updateContentRatio(videoSize: VideoSize) {
val newRatio = videoSize.getRatio() val newRatio = videoSize.getRatio()
val ratio = if(newRatio.isNaN()) currentContentRatio else newRatio val ratio = if (newRatio.isNaN()) currentContentRatio else newRatio
currentContentRatio = ratio currentContentRatio = ratio
Log.d(TAG, "Update Content ratio: $ratio") Log.d(TAG, "Update Content ratio: $ratio")
mutableUiState.update { mutableUiState.update {
@ -217,6 +228,26 @@ class VideoPlayerViewModelImpl @Inject constructor(
Log.e(TAG, "implement next stream") Log.e(TAG, "implement next stream")
} }
override fun showUi() {
mutableUiState.update {
it.copy(uiVissible = true)
}
uiVisibilityJob?.cancel()
uiVisibilityJob = viewModelScope.launch {
delay(2000)
mutableUiState.update {
it.copy(uiVissible = false)
}
}
}
override fun hideUi() {
uiVisibilityJob?.cancel()
mutableUiState.update {
it.copy(uiVissible = false)
}
}
override fun switchToEmbeddedView() { override fun switchToEmbeddedView() {
fullscreenListener?.onFullscreenToggle(false) fullscreenListener?.onFullscreenToggle(false)
mutableUiState.update { mutableUiState.update {
@ -267,6 +298,14 @@ class VideoPlayerViewModelImpl @Inject constructor(
println("dummy impl") println("dummy impl")
} }
override fun showUi() {
println("dummy impl")
}
override fun hideUi() {
println("dummy impl")
}
override fun pause() { override fun pause() {
println("dummy pause") println("dummy pause")
} }

View File

@ -18,10 +18,11 @@
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>. * along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
*/ */
package net.newpipe.newplayer.ui package net.newpipe.newplayer.ui
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -85,51 +86,58 @@ import net.newpipe.newplayer.ui.theme.video_player_onSurface
fun VideoPlayerControllerUI( fun VideoPlayerControllerUI(
isPlaying: Boolean, isPlaying: Boolean,
fullscreen: Boolean, fullscreen: Boolean,
uiVissible: Boolean,
play: () -> Unit, play: () -> Unit,
pause: () -> Unit, pause: () -> Unit,
prevStream: () -> Unit, prevStream: () -> Unit,
nextStream: () -> Unit, nextStream: () -> Unit,
switchToFullscreen: () -> Unit, switchToFullscreen: () -> Unit,
switchToEmbeddedView: () -> Unit switchToEmbeddedView: () -> Unit,
showUi: () -> Unit,
hideUi: () -> Unit
) { ) {
Surface( TouchControll(modifier = Modifier, hideUi = hideUi, showUi = showUi, uiVissible = uiVissible) {
modifier = Modifier.fillMaxSize(), color = Color(0x75000000) if (uiVissible) {
) { Surface(
Box( modifier = Modifier.fillMaxSize(), color = Color(0x75000000)
modifier = if (fullscreen) { ) {
Modifier Box(
.background(Color.Transparent) modifier = if (fullscreen) {
.windowInsetsPadding(WindowInsets.systemBars) Modifier
} else { .background(Color.Transparent)
Modifier .windowInsetsPadding(WindowInsets.systemBars)
.background(Color.Transparent) } else {
Modifier
.background(Color.Transparent)
}
) {
TopUI(
modifier = Modifier
.align(Alignment.TopStart)
.fillMaxWidth()
.defaultMinSize(minHeight = 45.dp)
.padding(top = 4.dp, start = 16.dp, end = 16.dp)
)
CenterUI(
modifier = Modifier.align(Alignment.Center),
isPlaying,
play = play,
pause = pause,
prevStream = prevStream,
nextStream = nextStream
)
BottomUI(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(start = 16.dp, end = 16.dp)
.defaultMinSize(minHeight = 40.dp)
.fillMaxWidth(),
isFullscreen = fullscreen,
switchToFullscreen,
switchToEmbeddedView
)
}
} }
) {
TopUI(
modifier = Modifier
.align(Alignment.TopStart)
.fillMaxWidth()
.defaultMinSize(minHeight = 45.dp)
.padding(top = 4.dp, start = 16.dp, end = 16.dp)
)
CenterUI(
modifier = Modifier.align(Alignment.Center),
isPlaying,
play = play,
pause = pause,
prevStream = prevStream,
nextStream = nextStream
)
BottomUI(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(start = 16.dp, end = 16.dp)
.defaultMinSize(minHeight = 40.dp)
.fillMaxWidth(),
isFullscreen = fullscreen,
switchToFullscreen,
switchToEmbeddedView
)
} }
} }
if (fullscreen) { if (fullscreen) {
@ -196,6 +204,26 @@ private fun TopUI(modifier: Modifier) {
} }
} }
@Composable
private fun TouchControll(
modifier: Modifier,
hideUi: () -> Unit,
showUi: () -> kotlin.Unit,
uiVissible: Boolean,
content: @Composable () -> Unit
) {
Box(modifier = Modifier
.fillMaxSize()
.clickable {
if (uiVissible)
hideUi()
else
showUi()
}) {
content()
}
}
@Composable @Composable
private fun MainMenu() { private fun MainMenu() {
var showMainMenu: Boolean by remember { mutableStateOf(false) } var showMainMenu: Boolean by remember { mutableStateOf(false) }
@ -399,12 +427,15 @@ fun VideoPlayerControllerUIPreviewEmbeded() {
PreviewBackgroundSurface { PreviewBackgroundSurface {
VideoPlayerControllerUI(isPlaying = false, VideoPlayerControllerUI(isPlaying = false,
fullscreen = false, fullscreen = false,
uiVissible = true,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},
nextStream = {}, nextStream = {},
switchToFullscreen = {}, switchToFullscreen = {},
switchToEmbeddedView = {}) switchToEmbeddedView = {},
showUi = {},
hideUi = {})
} }
} }
} }
@ -416,12 +447,15 @@ fun VideoPlayerControllerUIPreviewLandscape() {
PreviewBackgroundSurface { PreviewBackgroundSurface {
VideoPlayerControllerUI(isPlaying = true, VideoPlayerControllerUI(isPlaying = true,
fullscreen = true, fullscreen = true,
uiVissible = true,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},
nextStream = {}, nextStream = {},
switchToEmbeddedView = {}, switchToEmbeddedView = {},
switchToFullscreen = {}) switchToFullscreen = {},
showUi = {},
hideUi = {})
} }
} }
} }
@ -434,12 +468,15 @@ fun VideoPlayerControllerUIPreviewPortrait() {
VideoPlayerControllerUI( VideoPlayerControllerUI(
isPlaying = false, isPlaying = false,
fullscreen = true, fullscreen = true,
uiVissible = true,
play = {}, play = {},
pause = {}, pause = {},
prevStream = {}, prevStream = {},
nextStream = {}, nextStream = {},
switchToEmbeddedView = {}, switchToEmbeddedView = {},
switchToFullscreen = {}) switchToFullscreen = {},
showUi = {},
hideUi = {})
} }
} }
} }

View File

@ -121,12 +121,15 @@ fun VideoPlayerUI(
VideoPlayerControllerUI( VideoPlayerControllerUI(
isPlaying = uiState.playing, isPlaying = uiState.playing,
fullscreen = uiState.fullscreen, fullscreen = uiState.fullscreen,
uiVissible = uiState.uiVissible,
play = viewModel::play, play = viewModel::play,
pause = viewModel::pause, pause = viewModel::pause,
prevStream = viewModel::prevStream, prevStream = viewModel::prevStream,
nextStream = viewModel::nextStream, nextStream = viewModel::nextStream,
switchToFullscreen = viewModel::switchToFullscreen, switchToFullscreen = viewModel::switchToFullscreen,
switchToEmbeddedView = viewModel::switchToEmbeddedView switchToEmbeddedView = viewModel::switchToEmbeddedView,
showUi = viewModel::showUi,
hideUi = viewModel::hideUi
) )
} }
} }