Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions common/src/main/res/drawable/ic_pause.xml
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: these are coming from Material Symbols.

Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
android:fillColor="@android:color/black"
android:pathData="M560,760L560,200L720,200L720,760L560,760ZM240,760L240,200L400,200L400,760L240,760Z" />
</vector>
9 changes: 5 additions & 4 deletions common/src/main/res/drawable/ic_play.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M8,5v14l11,-7z"/>
android:fillColor="@android:color/black"
android:pathData="M320,760L320,200L760,480L320,760Z" />
</vector>
Original file line number Diff line number Diff line change
@@ -1,70 +1,139 @@
package com.theoplayer.sample.ui.fullscreen

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import com.google.android.material.button.MaterialButton
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import com.theoplayer.android.api.event.EventListener
import com.theoplayer.android.api.event.player.PlayerEvent
import com.theoplayer.android.api.event.player.PlayerEventTypes
import com.theoplayer.android.api.fullscreen.FullScreenActivity
import com.theoplayer.android.api.fullscreen.FullScreenManager
import com.theoplayer.android.api.player.Player

class CustomFullScreenActivity : FullScreenActivity() {
private lateinit var playPauseButton: MaterialButton
private lateinit var theoPlayer: Player
private lateinit var theoFullScreenManager: FullScreenManager

override fun onCreate(savedInstanceState: Bundle?) {
// Adding support for extended AppCompat features.
// It allows to use styles and themes defined for material components.
delegate.installViewFactory()
delegate.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)

// Inflating custom view.
val view = LayoutInflater.from(this).inflate(R.layout.activity_fullscreen, null, false)
delegate.addContentView(
view,
// Gathering THEO objects references.
theoPlayer = theOplayerView!!.player
theoFullScreenManager = theOplayerView!!.fullScreenManager

// Add custom overlay.
addContentView(
ComposeView(this).apply {
setContent {
MaterialTheme(colorScheme = darkColorScheme()) {
FullScreenOverlay(
player = theoPlayer,
fullScreenManager = theoFullScreenManager
)
}
}
},
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
)
}
}

// Gathering THEO objects references.
theoPlayer = theOplayerView!!.player
theoFullScreenManager = theOplayerView!!.fullScreenManager

// Configuring UI behavior.
playPauseButton = view.findViewById(R.id.playPauseButton)
val exitFullScreenButton = view.findViewById<MaterialButton>(R.id.exitFullScreenButton)

adjustPlayPauseButtonIcon()
playPauseButton.setOnClickListener { onPlayPauseClick() }
exitFullScreenButton.setOnClickListener { onFullScreenExit() }

// Configuring THEOplayer.
theoPlayer.addEventListener(PlayerEventTypes.PLAY) { adjustPlayPauseButtonIcon() }
theoPlayer.addEventListener(PlayerEventTypes.PAUSE) { adjustPlayPauseButtonIcon() }
@Composable
fun FullScreenOverlay(
player: Player,
fullScreenManager: FullScreenManager
) {
val spaceMargin = dimensionResource(com.theoplayer.sample.common.R.dimen.spaceMargin)
Row(
modifier = Modifier.padding(spaceMargin),
horizontalArrangement = Arrangement.spacedBy(spaceMargin)
) {
PlayButton(player = player)
ExitFullscreenButton(fullScreenManager = fullScreenManager)
}
}

private fun onFullScreenExit() {
theoFullScreenManager.exitFullScreen()
@Composable
fun PlayButton(
modifier: Modifier = Modifier,
player: Player
) {
val paused = rememberPaused(player)
FilledIconButton(
modifier = modifier,
onClick = {
if (player.isPaused) {
player.play()
} else {
player.pause()
}
}
) {
Icon(
painter = painterResource(
if (paused) {
com.theoplayer.sample.common.R.drawable.ic_play
} else {
com.theoplayer.sample.common.R.drawable.ic_pause
}
),
contentDescription = if (paused) "Play" else "Pause"
)
}
}

private fun onPlayPauseClick() {
if (theoPlayer.isPaused) {
theoPlayer.play()
} else {
theoPlayer.pause()
@Composable
fun ExitFullscreenButton(
modifier: Modifier = Modifier,
fullScreenManager: FullScreenManager
) {
FilledIconButton(
modifier = modifier,
onClick = {
fullScreenManager.exitFullScreen()
}
) {
Icon(
painter = painterResource(com.theoplayer.sample.common.R.drawable.ic_fullscreen_exit),
contentDescription = "Exit fullscreen"
)
}
}

private fun adjustPlayPauseButtonIcon() {
if (theoPlayer.isPaused) {
playPauseButton.setIconResource(com.theoplayer.sample.common.R.drawable.ic_play)
} else {
playPauseButton.setIconResource(com.theoplayer.sample.common.R.drawable.ic_pause)
/**
* Returns whether the player is [paused][Player.isPaused].
* Updates automatically.
*/
@Composable
fun rememberPaused(player: Player): Boolean {
var paused by remember { mutableStateOf(player.isPaused) }
DisposableEffect(player) {
val listener = EventListener<PlayerEvent<*>> { paused = player.isPaused }
player.addEventListener(PlayerEventTypes.PLAY, listener)
player.addEventListener(PlayerEventTypes.PAUSE, listener)
onDispose {
player.removeEventListener(PlayerEventTypes.PLAY, listener)
player.removeEventListener(PlayerEventTypes.PAUSE, listener)
}
}
return paused
}
24 changes: 0 additions & 24 deletions full-screen-handling/src/main/res/layout/activity_fullscreen.xml

This file was deleted.