Skip to content

Commit

Permalink
[Jetcaster] Add support for playing an episode (mock)
Browse files Browse the repository at this point in the history
  • Loading branch information
arriolac committed Mar 22, 2024
1 parent c9537eb commit 78a8358
Show file tree
Hide file tree
Showing 10 changed files with 468 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ fun JetcasterApp(
)
)
PlayerScreen(
playerViewModel,
windowSizeClass,
displayFeatures,
playerViewModel,
onBackPress = appState::navigateBack
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.example.jetcaster.ui.player
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
Expand Down Expand Up @@ -49,11 +50,11 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Replay10
import androidx.compose.material.icons.filled.SkipNext
import androidx.compose.material.icons.filled.SkipPrevious
import androidx.compose.material.icons.rounded.PauseCircleFilled
import androidx.compose.material.icons.rounded.PlayCircleFilled
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Surface
Expand All @@ -62,6 +63,7 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -99,13 +101,21 @@ import java.time.Duration
*/
@Composable
fun PlayerScreen(
viewModel: PlayerViewModel,
windowSizeClass: WindowSizeClass,
displayFeatures: List<DisplayFeature>,
viewModel: PlayerViewModel,
onBackPress: () -> Unit
) {
val uiState = viewModel.uiState
PlayerScreen(uiState, windowSizeClass, displayFeatures, onBackPress)
PlayerScreen(
uiState,
windowSizeClass,
displayFeatures,
onBackPress,
onPlayPress = viewModel::onPlay,
onPausePress = viewModel::onPause,
onStop = viewModel::onStop
)
}

/**
Expand All @@ -117,11 +127,26 @@ private fun PlayerScreen(
windowSizeClass: WindowSizeClass,
displayFeatures: List<DisplayFeature>,
onBackPress: () -> Unit,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
onStop: () -> Unit,
modifier: Modifier = Modifier
) {
DisposableEffect(Unit) {
onDispose {
onStop()
}
}
Surface(modifier) {
if (uiState.podcastName.isNotEmpty()) {
PlayerContent(uiState, windowSizeClass, displayFeatures, onBackPress)
PlayerContent(
uiState,
windowSizeClass,
displayFeatures,
onBackPress,
onPlayPress,
onPausePress
)
} else {
FullScreenLoading()
}
Expand All @@ -134,6 +159,8 @@ fun PlayerContent(
windowSizeClass: WindowSizeClass,
displayFeatures: List<DisplayFeature>,
onBackPress: () -> Unit,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
modifier: Modifier = Modifier
) {
val foldingFeature = displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull()
Expand Down Expand Up @@ -162,7 +189,12 @@ fun PlayerContent(
PlayerContentTableTopTop(uiState = uiState)
},
second = {
PlayerContentTableTopBottom(uiState = uiState, onBackPress = onBackPress)
PlayerContentTableTopBottom(
uiState = uiState,
onBackPress = onBackPress,
onPlayPress = onPlayPress,
onPausePress = onPausePress
)
},
strategy = VerticalTwoPaneStrategy(splitFraction = 0.5f),
displayFeatures = displayFeatures,
Expand All @@ -186,15 +218,25 @@ fun PlayerContent(
PlayerContentBookStart(uiState = uiState)
},
second = {
PlayerContentBookEnd(uiState = uiState)
PlayerContentBookEnd(
uiState = uiState,
onPlayPress = onPlayPress,
onPausePress = onPausePress
)
},
strategy = HorizontalTwoPaneStrategy(splitFraction = 0.5f),
displayFeatures = displayFeatures
)
}
}
} else {
PlayerContentRegular(uiState, onBackPress, modifier)
PlayerContentRegular(
uiState,
onBackPress,
onPlayPress,
onPausePress,
modifier
)
}
}

Expand All @@ -205,6 +247,8 @@ fun PlayerContent(
private fun PlayerContentRegular(
uiState: PlayerUiState,
onBackPress: () -> Unit,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
Expand Down Expand Up @@ -235,8 +279,16 @@ private fun PlayerContentRegular(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.weight(10f)
) {
PlayerSlider(uiState.duration)
PlayerButtons(Modifier.padding(vertical = 8.dp))
PlayerSlider(
timeElapsed = uiState.timeElapsed,
episodeDuration = uiState.duration
)
PlayerButtons(
isPlaying = uiState.isPlaying,
onPlayPress = onPlayPress,
onPausePress = onPausePress,
Modifier.padding(vertical = 8.dp)
)
}
Spacer(modifier = Modifier.weight(1f))
}
Expand Down Expand Up @@ -279,6 +331,8 @@ private fun PlayerContentTableTopTop(
private fun PlayerContentTableTopBottom(
uiState: PlayerUiState,
onBackPress: () -> Unit,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
modifier: Modifier = Modifier
) {
// Content for the table part of the screen
Expand All @@ -303,8 +357,17 @@ private fun PlayerContentTableTopBottom(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.weight(10f)
) {
PlayerButtons(playerButtonSize = 92.dp, modifier = Modifier.padding(top = 8.dp))
PlayerSlider(uiState.duration)
PlayerButtons(
isPlaying = uiState.isPlaying,
onPlayPress = onPlayPress,
onPausePress = onPausePress,
playerButtonSize = 92.dp,
modifier = Modifier.padding(top = 8.dp)
)
PlayerSlider(
timeElapsed = uiState.timeElapsed,
episodeDuration = uiState.duration
)
}
}
}
Expand Down Expand Up @@ -344,6 +407,8 @@ private fun PlayerContentBookStart(
@Composable
private fun PlayerContentBookEnd(
uiState: PlayerUiState,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
Expand All @@ -359,8 +424,16 @@ private fun PlayerContentBookEnd(
.padding(vertical = 16.dp)
.weight(1f)
)
PlayerSlider(uiState.duration)
PlayerButtons(Modifier.padding(vertical = 8.dp))
PlayerSlider(
timeElapsed = uiState.timeElapsed,
episodeDuration = uiState.duration
)
PlayerButtons(
isPlaying = uiState.isPlaying,
onPlayPress = onPlayPress,
onPausePress = onPausePress,
Modifier.padding(vertical = 8.dp)
)
}
}

Expand Down Expand Up @@ -462,25 +535,40 @@ private fun PodcastInformation(
}
}

fun Duration.formatString() : String {
val minutes = this.toMinutes().toString().padStart(2, '0')
val secondsLeft = (this.toSeconds() % 60).toString().padStart(2, '0')
return "$minutes:$secondsLeft"
}

@Composable
private fun PlayerSlider(episodeDuration: Duration?) {
if (episodeDuration != null) {
Column(Modifier.fillMaxWidth()) {
Slider(value = 0f, onValueChange = { })
Row(Modifier.fillMaxWidth()) {
Text(text = "0s")
Spacer(modifier = Modifier.weight(1f))
Text("${episodeDuration.seconds}s")
}
private fun PlayerSlider(timeElapsed: Duration?, episodeDuration: Duration?) {
Column(Modifier.fillMaxWidth()) {
Row(Modifier.fillMaxWidth()) {
Text(
text = "${timeElapsed?.formatString()}${episodeDuration?.formatString()}",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
val sliderValue = (timeElapsed?.toSeconds() ?: 0).toFloat()
val maxRange = (episodeDuration?.toSeconds() ?: 0).toFloat()
Slider(
value = sliderValue,
valueRange = 0f..maxRange,
onValueChange = { }
)
}
}

@Composable
private fun PlayerButtons(
isPlaying: Boolean,
onPlayPress: () -> Unit,
onPausePress: () -> Unit,
modifier: Modifier = Modifier,
playerButtonSize: Dp = 72.dp,
sideButtonSize: Dp = 48.dp
sideButtonSize: Dp = 48.dp,
) {
Row(
modifier = modifier.fillMaxWidth(),
Expand All @@ -495,37 +583,55 @@ private fun PlayerButtons(
imageVector = Icons.Filled.SkipPrevious,
contentDescription = stringResource(R.string.cd_skip_previous),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(LocalContentColor.current),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
modifier = buttonsModifier
)
Image(
imageVector = Icons.Filled.Replay10,
contentDescription = stringResource(R.string.cd_reply10),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(LocalContentColor.current),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
modifier = buttonsModifier
)
Image(
imageVector = Icons.Rounded.PlayCircleFilled,
contentDescription = stringResource(R.string.cd_play),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(LocalContentColor.current),
modifier = Modifier
.size(playerButtonSize)
.semantics { role = Role.Button }
)
if (isPlaying) {
Image(
imageVector = Icons.Rounded.PauseCircleFilled,
contentDescription = stringResource(R.string.cd_pause),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primaryContainer),
modifier = Modifier
.size(playerButtonSize)
.semantics { role = Role.Button }
.clickable {
onPausePress()
}
)
} else {
Image(
imageVector = Icons.Rounded.PlayCircleFilled,
contentDescription = stringResource(R.string.cd_play),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primaryContainer),
modifier = Modifier
.size(playerButtonSize)
.semantics { role = Role.Button }
.clickable {
onPlayPress()
}
)
}
Image(
imageVector = Icons.Filled.Forward30,
contentDescription = stringResource(R.string.cd_forward30),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(LocalContentColor.current),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
modifier = buttonsModifier
)
Image(
imageVector = Icons.Filled.SkipNext,
contentDescription = stringResource(R.string.cd_skip_next),
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(LocalContentColor.current),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
modifier = buttonsModifier
)
}
Expand Down Expand Up @@ -557,7 +663,11 @@ fun TopAppBarPreview() {
@Composable
fun PlayerButtonsPreview() {
JetcasterTheme {
PlayerButtons()
PlayerButtons(
isPlaying = true,
onPlayPress = {},
onPausePress = {}
)
}
}

Expand All @@ -574,11 +684,15 @@ fun PlayerScreenPreview() {
PlayerUiState(
title = "Title",
duration = Duration.ofHours(2),
podcastName = "Podcast"
podcastName = "Podcast",
isPlaying = false,
),
displayFeatures = emptyList(),
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)),
onBackPress = { }
onBackPress = { },
onPlayPress = {},
onPausePress = {},
onStop = {},
)
}
}
Expand Down
Loading

0 comments on commit 78a8358

Please sign in to comment.