Skip to content

Commit

Permalink
feat: Pause and Resume.
Browse files Browse the repository at this point in the history
  • Loading branch information
oxyroid committed May 18, 2024
1 parent 5772da4 commit b4c11fa
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 22 deletions.
1 change: 1 addition & 0 deletions data/src/main/java/com/m3u/data/service/PlayerManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface PlayerManager {

val playbackState: StateFlow<@Player.State Int>
val playbackException: StateFlow<PlaybackException?>
val isPlaying: StateFlow<Boolean>

val tracksGroups: StateFlow<List<Tracks.Group>>
val cacheSpace: Flow<Long>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class PlayerManagerImpl @Inject constructor(

override val playbackState = MutableStateFlow<@Player.State Int>(Player.STATE_IDLE)
override val playbackException = MutableStateFlow<PlaybackException?>(null)
override val isPlaying = MutableStateFlow(false)
override val tracksGroups = MutableStateFlow<List<Tracks.Group>>(emptyList())

private var currentConnectTimeout = preferences.connectTimeout
Expand Down Expand Up @@ -434,9 +435,14 @@ class PlayerManagerImpl @Inject constructor(

override fun onTracksChanged(tracks: Tracks) {
super.onTracksChanged(tracks)
player.value?.isPlaying
tracksGroups.value = tracks.groups
}

override fun onIsPlayingChanged(isPlaying: Boolean) {
this.isPlaying.value = isPlaying
}

override fun pauseOrContinue(value: Boolean) {
player.value?.apply {
if (!value) pause() else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ internal data class PlayerState(
val playState: @Player.State Int = Player.STATE_IDLE,
val videoSize: Rect = Rect(),
val playerError: PlaybackException? = null,
val player: Player? = null
val player: Player? = null,
val isPlaying: Boolean = false
)
99 changes: 81 additions & 18 deletions features/stream/src/main/java/com/m3u/features/stream/StreamMask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -30,7 +28,9 @@ import androidx.compose.material.icons.rounded.Cast
import androidx.compose.material.icons.rounded.DarkMode
import androidx.compose.material.icons.rounded.HighQuality
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.material.icons.rounded.Pause
import androidx.compose.material.icons.rounded.PictureInPicture
import androidx.compose.material.icons.rounded.PlayArrow
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.ScreenRotationAlt
import androidx.compose.material.icons.rounded.Star
Expand Down Expand Up @@ -65,6 +65,9 @@ import androidx.media3.common.Player
import com.m3u.core.architecture.preferences.hiltPreferences
import com.m3u.core.util.basic.isNotEmpty
import com.m3u.data.television.model.RemoteDirection
import com.m3u.features.stream.MaskCenterState.Pause
import com.m3u.features.stream.MaskCenterState.Play
import com.m3u.features.stream.MaskCenterState.Replay
import com.m3u.features.stream.components.MaskTextButton
import com.m3u.features.stream.components.PlayerMask
import com.m3u.i18n.R.string
Expand Down Expand Up @@ -305,22 +308,20 @@ internal fun StreamMask(
}
},
body = {
AnimatedVisibility(
visible = (!isPanelExpanded && preferences.alwaysShowReplay) || playerState.playState in arrayOf(
Player.STATE_IDLE,
Player.STATE_ENDED
) || playerState.playerError != null,
enter = fadeIn() + scaleIn(initialScale = 0.85f),
exit = fadeOut() + scaleOut(targetScale = 0.85f)
) {
MaskCircleButton(
state = maskState,
icon = Icons.Rounded.Refresh,
onClick = {
coroutineScope.launch { helper.replay() }
}
)
}
val maskCenterState = MaskCenterState.of(
playerState.playState,
playerState.isPlaying,
preferences.alwaysShowReplay,
isPanelExpanded,
playerState.playerError
)
MaskCenterButton(
maskCenterState = maskCenterState,
maskState = maskState,
onPlay = { playerState.player?.play() },
onPause = { playerState.player?.pause() },
onRetry = { coroutineScope.launch { helper.replay() } }
)
},
footer = {
if (preferences.fullInfoPlayer && cover.isNotEmpty()) {
Expand Down Expand Up @@ -497,3 +498,65 @@ internal fun StreamMask(
)
}
}

@Composable
private fun MaskCenterButton(
maskCenterState: MaskCenterState?,
maskState: MaskState,
modifier: Modifier = Modifier,
onPlay: () -> Unit,
onPause: () -> Unit,
onRetry: () -> Unit
) {
Box(modifier) {
when (maskCenterState) {
Replay -> {
MaskCircleButton(
state = maskState,
icon = Icons.Rounded.Refresh,
onClick = onRetry
)
}

Play -> {
MaskCircleButton(
state = maskState,
icon = Icons.Rounded.PlayArrow,
onClick = onPlay
)
}

Pause -> {
MaskCircleButton(
state = maskState,
icon = Icons.Rounded.Pause,
onClick = onPause
)
}

else -> {}
}
}
}

private enum class MaskCenterState {
Replay, Play, Pause;

companion object {
fun of(
@Player.State playState: Int,
isPlaying: Boolean,
alwaysShowReplay: Boolean,
isPanelExpanded: Boolean,
playerError: Exception?
): MaskCenterState? = when {
isPanelExpanded || playState == Player.STATE_BUFFERING -> null
alwaysShowReplay || playState in arrayOf(
Player.STATE_IDLE,
Player.STATE_ENDED
) || playerError != null -> Replay

else -> if (!isPlaying) Play else Pause
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@ class StreamViewModel @Inject constructor(
playerManager.player,
playerManager.playbackState,
playerManager.size,
playerManager.playbackException
) { player, playState, videoSize, playbackException ->
playerManager.playbackException,
playerManager.isPlaying
) { player, playState, videoSize, playbackException, isPlaying ->
PlayerState(
playState = playState,
videoSize = videoSize,
playerError = playbackException,
player = player
player = player,
isPlaying = isPlaying
)
}
.stateIn(
Expand Down

0 comments on commit b4c11fa

Please sign in to comment.