add touchable surface
This commit is contained in:
parent
b5b75558b5
commit
5a2f62b55e
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue