Skip to content

Commit

Permalink
Merge pull request #29 from THEOplayer/feature/ads
Browse files Browse the repository at this point in the history
Basic ad support
  • Loading branch information
GillesMoris-Dolby authored Aug 12, 2024
2 parents 6bb7750 + 83b7b54 commit 1f8bb32
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 45 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
> - 🏠 Internal
> - 💅 Polish
## Unreleased

* 💥 Updated to Jetpack Compose version 1.6.8 ([BOM](https://developer.android.com/jetpack/compose/bom) 2024.06.00).
* 🚀 Added basic support for advertisements. (Requires THEOplayer SDK version 7.10.0 or higher.)

## v1.6.0 (2024-04-16)

* 🚀 Added support for THEOplayer Android SDK version 7.
Expand Down
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,6 @@ dependencies {
"mavenImplementation"("com.theoplayer.android-ui:android-ui:1.+")

implementation(libs.theoplayer)
implementation(libs.theoplayer.ads)
implementation(libs.theoplayer.ads.ima)
}
153 changes: 127 additions & 26 deletions app/src/main/java/com/theoplayer/android/ui/demo/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ package com.theoplayer.android.ui.demo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Brush
import androidx.compose.material.icons.rounded.Movie
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.theoplayer.android.api.THEOplayerConfig
import com.theoplayer.android.api.source.SourceDescription
import com.theoplayer.android.api.source.TypedSource
import com.theoplayer.android.api.ads.ima.GoogleImaIntegrationFactory
import com.theoplayer.android.ui.DefaultUI
import com.theoplayer.android.ui.demo.nitflex.NitflexUI
import com.theoplayer.android.ui.demo.nitflex.theme.NitflexTheme
Expand All @@ -37,14 +45,17 @@ class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainContent() {
val source = SourceDescription.Builder(
TypedSource.Builder("https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8")
.build()
).build()
var stream by rememberSaveable(stateSaver = StreamSaver) { mutableStateOf(streams.first()) }
var streamMenuOpen by remember { mutableStateOf(false) }

val player = rememberPlayer()
LaunchedEffect(player, source) {
player.source = source
LaunchedEffect(player) {
player.theoplayerView?.let { theoplayerView ->
theoplayerView.player.addIntegration(GoogleImaIntegrationFactory.createGoogleImaIntegration(theoplayerView))
}
}
LaunchedEffect(player, stream) {
player.source = stream.source
}

var themeMenuOpen by remember { mutableStateOf(false) }
Expand All @@ -61,27 +72,20 @@ fun MainContent() {
},
actions = {
IconButton(onClick = {
player.source = source
player.source = stream.source
player.play()
}) {
Icon(Icons.Rounded.Refresh, contentDescription = "Reload")
}
IconButton(onClick = { streamMenuOpen = true }) {
Icon(Icons.Rounded.Movie, contentDescription = "Stream")
}
IconButton(onClick = { themeMenuOpen = true }) {
Icon(Icons.Rounded.Brush, contentDescription = "Theme")
}
DropdownMenu(
expanded = themeMenuOpen,
onDismissRequest = { themeMenuOpen = false }) {
DropdownMenuItem(
text = { Text(text = "Default theme") },
onClick = { theme = PlayerTheme.Default })
DropdownMenuItem(
text = { Text(text = "Nitflex theme") },
onClick = { theme = PlayerTheme.Nitflex })
}
}
)
}, content = { padding ->
}) { padding ->
val playerModifier = Modifier
.padding(padding)
.fillMaxSize(1f)
Expand All @@ -90,7 +94,7 @@ fun MainContent() {
DefaultUI(
modifier = playerModifier,
player = player,
title = "Elephant's Dream"
title = stream.title
)
}

Expand All @@ -99,18 +103,115 @@ fun MainContent() {
NitflexUI(
modifier = playerModifier,
player = player,
title = "Elephant's Dream"
title = stream.title
)
}
}
}

if (streamMenuOpen) {
SelectStreamDialog(
streams = streams,
currentStream = stream,
onSelectStream = {
stream = it
streamMenuOpen = false
},
onDismissRequest = { streamMenuOpen = false }
)
}
if (themeMenuOpen) {
SelectThemeDialog(
currentTheme = theme,
onSelectTheme = {
theme = it
themeMenuOpen = false
},
onDismissRequest = { themeMenuOpen = false }
)
}
}
}
}

enum class PlayerTheme(val title: String) {
Default(title = "Default theme"),
Nitflex(title = "Nitflex theme")
}

@Composable
fun SelectStreamDialog(
streams: List<Stream>,
currentStream: Stream,
onSelectStream: (Stream) -> Unit,
onDismissRequest: () -> Unit,
) {
Dialog(onDismissRequest = onDismissRequest) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Select a stream",
style = MaterialTheme.typography.headlineSmall
)
LazyColumn {
items(items = streams) {
ListItem(
headlineContent = { Text(text = it.title) },
leadingContent = {
RadioButton(
selected = (it == currentStream),
onClick = null
)
},
modifier = Modifier.clickable(onClick = {
onSelectStream(it)
})
)
}
}
}
})
}
}
}

enum class PlayerTheme {
Default,
Nitflex
@Composable
fun SelectThemeDialog(
currentTheme: PlayerTheme,
onSelectTheme: (PlayerTheme) -> Unit,
onDismissRequest: () -> Unit,
) {
Dialog(onDismissRequest = onDismissRequest) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Select a theme",
style = MaterialTheme.typography.headlineSmall
)
LazyColumn {
items(items = PlayerTheme.values()) {
ListItem(
headlineContent = { Text(text = it.title) },
leadingContent = {
RadioButton(
selected = (it == currentTheme),
onClick = null
)
},
modifier = Modifier.clickable(onClick = {
onSelectTheme(it)
})
)
}
}
}
}
}
}

@Preview(showBackground = true)
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/com/theoplayer/android/ui/demo/Streams.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.theoplayer.android.ui.demo

import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.SaverScope
import com.theoplayer.android.api.source.SourceDescription
import com.theoplayer.android.api.source.TypedSource
import com.theoplayer.android.api.source.addescription.GoogleImaAdDescription

data class Stream(val title: String, val source: SourceDescription)

val streams by lazy {
listOf(
Stream(
title = "Elephant's Dream (HLS)",
source = SourceDescription.Builder(
TypedSource.Builder("https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8")
.build()
).build()
),
Stream(
title = "Sintel (DASH) with preroll ad",
source = SourceDescription.Builder(
TypedSource.Builder("https://cdn.theoplayer.com/video/dash/webvtt-embedded-in-isobmff/Manifest.mpd")
.build()
).ads(
GoogleImaAdDescription.Builder("https://cdn.theoplayer.com/demos/ads/vast/dfp-preroll-no-skip.xml")
.timeOffset("start")
.build()
).build()
)
)
}

object StreamSaver : Saver<Stream, Int> {
override fun restore(value: Int): Stream? = streams.getOrNull(value)
override fun SaverScope.save(value: Stream): Int = streams.indexOf(value)
}
18 changes: 10 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[versions]
gradle = "8.3.2"
kotlin-gradle-plugin = "1.8.10"
ktx = "1.12.0"
lifecycle-runtime = "2.7.0"
activity-compose = "1.8.2"
appcompat = "1.6.1"
compose-bom = "2024.04.00"
ktx = "1.13.1"
lifecycle-runtime = "2.8.4"
activity-compose = "1.9.1"
appcompat = "1.7.0"
compose-bom = "2024.06.00"
junit4 = "4.13.2"
ui-test-junit4 = "1.6.5" # ...not in BOM for some reason?
androidx-junit = "1.1.5"
androidx-espresso = "3.5.1"
ui-test-junit4 = "1.6.8" # ...not in BOM for some reason?
androidx-junit = "1.2.1"
androidx-espresso = "3.6.1"
dokka = "1.9.20"
theoplayer = "7.8.0"

Expand All @@ -35,6 +35,8 @@ dokka-plugin = { group = "org.jetbrains.dokka", name = "android-documentation-pl
kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin-gradle-plugin" }
junit4 = { group = "junit", name = "junit", version.ref = "junit4" }
theoplayer = { group = "com.theoplayer.theoplayer-sdk-android", name = "core", version.ref = "theoplayer" }
theoplayer-ads = { group = "com.theoplayer.theoplayer-sdk-android", name = "integration-ads", version.ref = "theoplayer" }
theoplayer-ads-ima = { group = "com.theoplayer.theoplayer-sdk-android", name = "integration-ads-ima", version.ref = "theoplayer" }

[plugins]
android-application = { id = "com.android.application", version.ref = "gradle" }
Expand Down
Loading

0 comments on commit 1f8bb32

Please sign in to comment.