From de798868ca5b13bd79c9b5f1aa14b9bb90edcec6 Mon Sep 17 00:00:00 2001 From: AbdallahMehiz Date: Sat, 24 Aug 2024 01:48:46 +0100 Subject: [PATCH] refactor: make player handle prop changes better * increase buttons tap size --- .../mehiz/mpvkt/ui/player/PlayerActivity.kt | 31 ++++++++++++- .../mehiz/mpvkt/ui/player/PlayerViewModel.kt | 36 +++++++--------- .../ui/player/controls/PlayerControls.kt | 43 +++++++++++-------- .../mpvkt/ui/player/controls/PlayerSheets.kt | 2 +- .../controls/components/ControlsButton.kt | 4 +- .../controls/components/sheets/MoreSheet.kt | 5 ++- 6 files changed, 77 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt index b7ede10..d210735 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt @@ -211,6 +211,9 @@ class PlayerActivity : AppCompatActivity() { MPVLib.setPropertyBoolean("input-default-bindings", true) player.addObserver(playerObserver) + additionalObservedProps.forEach { + MPVLib.observeProperty(it.key, it.value) + } } private fun setupAudio() { @@ -371,6 +374,11 @@ class PlayerActivity : AppCompatActivity() { return filepath } + override fun onConfigurationChanged(newConfig: Configuration) { + viewModel.changeVideoAspect(playerPreferences.videoAspect.get()) + super.onConfigurationChanged(newConfig) + } + @Suppress("ReturnCount") fun openContentFd(uri: Uri): String? { if (uri.scheme != "content") return null @@ -402,6 +410,7 @@ class PlayerActivity : AppCompatActivity() { "time-pos" -> viewModel.updatePlayBackPos(value.toFloat()) "demuxer-cache-time" -> viewModel.updateReadAhead(value = value) "duration" -> viewModel.duration.update { value.toFloat() } + "chapter" -> viewModel.updateChapter(value) } } @@ -439,9 +448,21 @@ class PlayerActivity : AppCompatActivity() { } } + val trackId: (String) -> Int? = { + when (it) { + "auto" -> null + "no" -> -1 + else -> it.toInt() + } + } + internal fun onObserverEvent(property: String, value: String) { when (property) { "speed" -> viewModel.playbackSpeed.update { value.toFloat() } + "hwdec-current" -> Decoder.entries.find { it.value == value }?.let { viewModel.updateDecoder(it) } + "aid" -> trackId(value)?.let { viewModel.selectAudio(it) } + "sid" -> trackId(value)?.let { viewModel.setSubtitle(it, viewModel.selectedSubtitles.value.second) } + "secondary-sid" -> trackId(value)?.let { viewModel.setSubtitle(viewModel.selectedSubtitles.value.first, it) } } } @@ -459,10 +480,8 @@ class PlayerActivity : AppCompatActivity() { } setOrientation() viewModel.changeVideoAspect(playerPreferences.videoAspect.get()) - viewModel.duration.value = player.duration!!.toFloat() viewModel.loadChapters() viewModel.loadTracks() - viewModel.getDecoder() } MPVLib.mpvEventId.MPV_EVENT_SEEK -> { @@ -649,4 +668,12 @@ class PlayerActivity : AppCompatActivity() { companion object { const val TAG = "mpvKt" } + + private val additionalObservedProps = mapOf( + "chapter" to MPVLib.mpvFormat.MPV_FORMAT_INT64, + "sid" to MPVLib.mpvFormat.MPV_FORMAT_STRING, + "secondary-sid" to MPVLib.mpvFormat.MPV_FORMAT_STRING, + "aid" to MPVLib.mpvFormat.MPV_FORMAT_STRING, + "hwdec-current" to MPVLib.mpvFormat.MPV_FORMAT_STRING + ) } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt index 4cd4582..e4f489f 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt @@ -37,7 +37,7 @@ class PlayerViewModel( private val _subtitleTracks = MutableStateFlow>(emptyList()) val subtitleTracks = _subtitleTracks.asStateFlow() - private val _selectedSubtitles = MutableStateFlow(listOf(-1, -1)) + private val _selectedSubtitles = MutableStateFlow(Pair(-1, -1)) val selectedSubtitles = _selectedSubtitles.asStateFlow() private val _audioTracks = MutableStateFlow>(emptyList()) @@ -100,10 +100,6 @@ class PlayerViewModel( timerJob?.cancel() } - fun getDecoder() { - _currentDecoder.update { getDecoderFromValue(activity.player.hwdecActive) } - } - fun cycleDecoders() { MPVLib.setPropertyString( "hwdec", @@ -172,7 +168,7 @@ class PlayerViewModel( } } _subtitleTracks.update { subTracks } - _selectedSubtitles.update { listOf(activity.player.sid, activity.player.secondarySid) } + _selectedSubtitles.update { Pair(activity.player.sid, activity.player.secondarySid) } _audioTracks.update { audioTracks } _selectedAudio.update { activity.player.aid } } @@ -182,19 +178,19 @@ class PlayerViewModel( val selectedSubs = selectedSubtitles.value _selectedSubtitles.update { when (id) { - selectedSubs[0] -> listOf(selectedSubs[1], -1) - selectedSubs[1] -> listOf(selectedSubs[0], -1) + selectedSubs.first -> Pair(selectedSubs.second, -1) + selectedSubs.second -> Pair(selectedSubs.first, -1) else -> { - if (selectedSubs[0] != -1) { - listOf(selectedSubs[0], id) + if (selectedSubs.first != -1) { + Pair(selectedSubs.first, id) } else { - listOf(id, -1) + Pair(id, -1) } } } } - activity.player.sid = _selectedSubtitles.value[0] - activity.player.secondarySid = _selectedSubtitles.value[1] + activity.player.sid = _selectedSubtitles.value.first + activity.player.secondarySid = _selectedSubtitles.value.second } fun loadChapters() { @@ -205,13 +201,10 @@ class PlayerViewModel( fun selectChapter(index: Int) { val time = chapters[index].time seekTo(time.toInt()) - updateChapter(time.toLong()) } - fun updateChapter(time: Long) { - runCatching { - _currentChapter.update { chapters.last { it.time <= time } } - } + fun updateChapter(index: Long) { + _currentChapter.update { chapters[index.toInt()] } } fun selectAudio(id: Int) { @@ -229,7 +222,11 @@ class PlayerViewModel( MPVLib.command(arrayOf("sub-add", path, "cached")) if (activity.player.sid != subtitleTracks.value.size + 1) return _subtitleTracks.update { it.plus(Track(activity.player.sid, path, null)) } - _selectedSubtitles.update { listOf(activity.player.sid, activity.player.secondarySid) } + _selectedSubtitles.update { Pair(activity.player.sid, activity.player.secondarySid) } + } + + fun setSubtitle(sid: Int, secondarySid: Int) { + _selectedSubtitles.update { Pair(sid, secondarySid) } } fun addAudio(uri: Uri) { @@ -247,7 +244,6 @@ class PlayerViewModel( fun updatePlayBackPos(pos: Float) { _pos.update { pos } - updateChapter(pos.toLong()) } fun updateReadAhead(value: Long) { diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerControls.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerControls.kt index 6524343..e6c3839 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerControls.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerControls.kt @@ -2,6 +2,8 @@ package live.mehiz.mpvkt.ui.player.controls import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.FiniteAnimationSpec +import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -134,8 +136,8 @@ fun PlayerControls( } AnimatedVisibility( isBrightnessSliderShown, - enter = slideInHorizontally { it } + fadeIn(), - exit = slideOutHorizontally { it } + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(brightnessSlider) { end.linkTo(parent.end, spacing.medium) top.linkTo(parent.top) @@ -145,8 +147,8 @@ fun PlayerControls( AnimatedVisibility( isVolumeSliderShown, - enter = slideInHorizontally { -it } + fadeIn(), - exit = slideOutHorizontally { -it } + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { -it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { -it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(volumeSlider) { start.linkTo(parent.start, spacing.medium) top.linkTo(parent.top) @@ -170,8 +172,8 @@ fun PlayerControls( } AnimatedVisibility( currentPlayerUpdate != PlayerUpdates.None, - enter = fadeIn(), - exit = fadeOut(), + enter = fadeIn(playControlsAnimationSpec()), + exit = fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(playerUpdates) { linkTo(parent.start, parent.end) linkTo(parent.top, parent.bottom, bias = 0.2f) @@ -200,8 +202,8 @@ fun PlayerControls( } AnimatedVisibility( visible = (controlsShown && !areControlsLocked) || isLoading, - enter = fadeIn(), - exit = fadeOut(), + enter = fadeIn(playControlsAnimationSpec()), + exit = fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(playerPauseButton) { end.linkTo(parent.absoluteRight) start.linkTo(parent.absoluteLeft) @@ -230,8 +232,8 @@ fun PlayerControls( } AnimatedVisibility( visible = (controlsShown || seekBarShown) && !areControlsLocked, - enter = slideInVertically(initialOffsetY = { it }) + fadeIn(), - exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(), + enter = slideInVertically(playControlsAnimationSpec()) { it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutVertically(playControlsAnimationSpec()) { it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(seekbar) { bottom.linkTo(parent.bottom, spacing.medium) }, @@ -256,8 +258,8 @@ fun PlayerControls( } AnimatedVisibility( controlsShown && !areControlsLocked, - enter = slideInHorizontally { -it } + fadeIn(), - exit = slideOutHorizontally { -it } + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { -it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { -it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(topLeftControls) { top.linkTo(parent.top, spacing.medium) start.linkTo(parent.start) @@ -268,8 +270,8 @@ fun PlayerControls( // Top right controls AnimatedVisibility( controlsShown && !areControlsLocked, - enter = slideInHorizontally(initialOffsetX = { it }) + fadeIn(), - exit = slideOutHorizontally(targetOffsetX = { it }) + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(topRightControls) { top.linkTo(parent.top, spacing.medium) end.linkTo(parent.end) @@ -278,8 +280,8 @@ fun PlayerControls( // Bottom right controls AnimatedVisibility( controlsShown && !areControlsLocked, - enter = slideInHorizontally(initialOffsetX = { it }) + fadeIn(), - exit = slideOutHorizontally(targetOffsetX = { it }) + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(bottomRightControls) { bottom.linkTo(seekbar.top) end.linkTo(seekbar.end) @@ -288,8 +290,8 @@ fun PlayerControls( // Bottom left controls AnimatedVisibility( controlsShown && !areControlsLocked, - enter = slideInHorizontally(initialOffsetX = { -it }) + fadeIn(), - exit = slideOutHorizontally(targetOffsetX = { -it }) + fadeOut(), + enter = slideInHorizontally(playControlsAnimationSpec()) { -it } + fadeIn(playControlsAnimationSpec()), + exit = slideOutHorizontally(playControlsAnimationSpec()) { -it } + fadeOut(playControlsAnimationSpec()), modifier = Modifier.constrainAs(bottomLeftControls) { bottom.linkTo(seekbar.top) start.linkTo(seekbar.start) @@ -302,3 +304,8 @@ fun PlayerControls( PlayerPanels() } } + +fun playControlsAnimationSpec(): FiniteAnimationSpec = tween( + durationMillis = 300, + easing = LinearOutSlowInEasing +) diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt index 8b059b8..c7c3780 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt @@ -42,7 +42,7 @@ fun PlayerSheets() { } SubtitlesSheet( tracks = subtitles.toImmutableList(), - selectedTracks = selectedSubs.toImmutableList(), + selectedTracks = selectedSubs.toList().toImmutableList(), onSelect = { viewModel.selectSub(it) }, onAddSubtitle = { subtitlesPicker.launch(arrayOf("*/*")) }, onOpenSubtitleSettings = { diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/ControlsButton.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/ControlsButton.kt index af657e8..49c98f8 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/ControlsButton.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/ControlsButton.kt @@ -49,7 +49,7 @@ fun ControlsButton( interactionSource = interactionSource, indication = rememberRipple(), ) - .padding(MaterialTheme.spacing.small), + .padding(MaterialTheme.spacing.medium), ) { Icon( icon, @@ -84,7 +84,7 @@ fun ControlsButton( interactionSource = interactionSource, indication = rememberRipple(), ) - .padding(MaterialTheme.spacing.small), + .padding(MaterialTheme.spacing.medium), ) { Text( text, diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt index 407240c..14f1f9b 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt @@ -97,7 +97,10 @@ fun MoreSheet( TimePickerDialog( remainingTime = remainingTime ?: 0, onDismissRequest = { isSleepTimerDialogShown = false }, - onTimeSelect = { viewModel.startTimer(it) } + onTimeSelect = { + if (it < 1) return@TimePickerDialog + viewModel.startTimer(it) + } ) } TextButton(onClick = onEnterFiltersPanel) {