Skip to content

Commit

Permalink
feat: create a PlayerControlsScaffold
Browse files Browse the repository at this point in the history
* Create a PlayerControlScaffold to define the playerOverlay
 layout
* Divide player components "MiddleControls", "BottomControls"
 into different files to make it more organized and easier to read
* Remove the customization modifier because it can be confusing and
each of your composable icons can have its own modifier set by whoever
creates it

Closes #32
  • Loading branch information
Thalys Matias Carrara committed Jun 5, 2023
1 parent 5ead26a commit 06b49d9
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class EnhancedVideoPlayerTest {
.assertIsDisplayed()
.performClick()

composeTestRule.onNodeWithTag("PlayerControlsParent").assertIsDisplayed()
composeTestRule.onNodeWithTag("PlayerControlsParent", useUnmergedTree = true)
.assertIsDisplayed()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import com.profusion.androidenhancedvideoplayer.components.ControlsCustomization
import com.profusion.androidenhancedvideoplayer.components.PlayerControls
import com.profusion.androidenhancedvideoplayer.components.playerOverlay.ControlsCustomization
import com.profusion.androidenhancedvideoplayer.components.playerOverlay.PlayerControls
import org.junit.Rule
import org.junit.Test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import com.profusion.androidenhancedvideoplayer.components.playerOverlay.ControlsCustomization
import com.profusion.androidenhancedvideoplayer.components.playerOverlay.PlayerControls
import com.profusion.androidenhancedvideoplayer.utils.setLandscape
import com.profusion.androidenhancedvideoplayer.utils.setPortrait

Expand Down Expand Up @@ -120,7 +122,7 @@ fun EnhancedVideoPlayer(
}
},
customization = controlsCustomization,
modifier = Modifier.matchParentSize()
modifier = Modifier.matchParentSize().testTag("PlayerControlsParent")
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.profusion.androidenhancedvideoplayer.components.playerOverlay

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.absolutePadding
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp

private val BOTTOM_CONTROLS_HEIGHT = 50.dp

@Composable
fun BottomControls(
modifier: Modifier = Modifier,
isFullScreen: Boolean,
onFullScreenToggle: () -> Unit,
customization: ControlsCustomization
) {
Box(
modifier = modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.absolutePadding(4.dp)
) {
IconButton(
onClick = onFullScreenToggle,
modifier = Modifier
.align(Alignment.CenterEnd)
.testTag("FullScreenToggleButton")
) {
when (isFullScreen) {
true -> customization.exitFullScreenIconContent()
false -> customization.fullScreenIconContent()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.profusion.androidenhancedvideoplayer.components.playerOverlay

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag

@Composable
fun MiddleControls(
modifier: Modifier = Modifier,
isPlaying: Boolean,
hasEnded: Boolean,
customization: ControlsCustomization,
onPreviousClick: () -> Unit,
onNextClick: () -> Unit,
onPauseToggle: () -> Unit
) {
Box(
modifier = modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
) {
IconButton(onClick = onPreviousClick) {
customization.previousIconContent()
}
IconButton(
onClick = onPauseToggle,
modifier = Modifier.testTag("PauseToggleButton")
) {
when {
hasEnded -> customization.replayIconContent()
isPlaying -> customization.pauseIconContent()
else -> customization.playIconContent()
}
}
IconButton(onClick = onNextClick) {
customization.nextIconContent()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.profusion.androidenhancedvideoplayer.components.playerOverlay

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview

class ControlsCustomization(
val previousIconContent: @Composable () -> Unit = { PreviousIcon() },
val playIconContent: @Composable () -> Unit = { PlayIcon() },
val pauseIconContent: @Composable () -> Unit = { PauseIcon() },
val replayIconContent: @Composable () -> Unit = { ReplayIcon() },
val nextIconContent: @Composable () -> Unit = { NextIcon() },
val fullScreenIconContent: @Composable () -> Unit = { FullScreenIcon() },
val exitFullScreenIconContent: @Composable () -> Unit = { ExitFullScreenIcon() }
)

@Composable
fun PlayerControls(
isVisible: Boolean,
isPlaying: Boolean,
isFullScreen: Boolean,
hasEnded: Boolean,
onPreviousClick: () -> Unit,
onPauseToggle: () -> Unit,
onNextClick: () -> Unit,
onFullScreenToggle: () -> Unit,
customization: ControlsCustomization,
modifier: Modifier = Modifier
) {
PlayerControlsScaffold(
modifier = modifier.testTag("PlayerControlsParent"),
isVisible = isVisible,
topContent = { /* TODO */ },
bottomContent = {
BottomControls(
isFullScreen = isFullScreen,
onFullScreenToggle = onFullScreenToggle,
customization = customization
)
}
) {
MiddleControls(
modifier = Modifier.weight(1f),
isPlaying = isPlaying,
hasEnded = hasEnded,
customization = customization,
onPreviousClick = onPreviousClick,
onNextClick = onNextClick,
onPauseToggle = onPauseToggle
)
}
}

@Preview(showBackground = true)
@Composable
private fun PreviewPlayerControls() {
PlayerControls(
isVisible = true,
isPlaying = true,
hasEnded = false,
isFullScreen = false,
onPreviousClick = {},
onPauseToggle = {},
onNextClick = {},
onFullScreenToggle = {},
customization = ControlsCustomization()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.profusion.androidenhancedvideoplayer.components.playerOverlay

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color

@Composable
fun PlayerControlsScaffold(
modifier: Modifier = Modifier,
isVisible: Boolean,
topContent: @Composable ColumnScope.() -> Unit,
bottomContent: @Composable ColumnScope.() -> Unit,
content: @Composable ColumnScope.() -> Unit
) {
AnimatedVisibility(
visible = isVisible,
enter = fadeIn(),
exit = fadeOut(),
modifier = modifier
.background(Color.Black.copy(alpha = 0.6f))
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween
) {
topContent()
content()
bottomContent()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.profusion.androidenhancedvideoplayer.components
package com.profusion.androidenhancedvideoplayer.components.playerOverlay

import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
Expand Down

0 comments on commit 06b49d9

Please sign in to comment.