Skip to content

Commit

Permalink
Display metrics overlay in the TV demo and add a dedicated setting (#666
Browse files Browse the repository at this point in the history
)
  • Loading branch information
MGaetan89 authored and StaehliJ committed Aug 28, 2024
1 parent 39b3f82 commit 97a5468
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.demo.ui.player.metrics
package ch.srgssr.pillarbox.demo.shared.ui.player.metrics

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import androidx.media3.common.Format
import ch.srgssr.pillarbox.demo.shared.ui.settings.MetricsOverlayOptions
import ch.srgssr.pillarbox.player.analytics.metrics.PlaybackMetrics
Expand Down Expand Up @@ -108,7 +107,12 @@ private fun OverlayText(
) {
BasicText(
modifier = modifier,
style = TextStyle.Default.copy(fontSize = overlayOptions.textSize),
style = overlayOptions.textStyle.copy(
shadow = Shadow(
color = Color.Black,
blurRadius = 4f,
),
),
color = { overlayOptions.textColor },
text = text,
)
Expand All @@ -117,7 +121,7 @@ private fun OverlayText(
@Preview
@Composable
private fun OverlayTextPreview() {
val overlayOptions = MetricsOverlayOptions(textColor = Color.Yellow, textSize = 12.sp)
val overlayOptions = MetricsOverlayOptions()
OverlayText(text = "Text; 12 ac1.mp3 channels:4 colors:4", overlayOptions = overlayOptions)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package ch.srgssr.pillarbox.demo.shared.ui.player.settings

import android.app.Application
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Analytics
import androidx.compose.material.icons.filled.ClosedCaption
import androidx.compose.material.icons.filled.RecordVoiceOver
import androidx.compose.material.icons.filled.SlowMotionVideo
Expand All @@ -16,7 +17,10 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.media3.common.C
import androidx.media3.common.Player
import androidx.media3.common.TrackSelectionParameters
import ch.srgssr.pillarbox.demo.shared.R
import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettings
import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettingsRepository
import ch.srgssr.pillarbox.player.extension.displayName
import ch.srgssr.pillarbox.player.extension.getPlaybackSpeed
import ch.srgssr.pillarbox.player.extension.isAudioTrackDisabled
Expand All @@ -41,16 +45,19 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

/**
* Player settings view model
*
* @constructor Create empty Player settings view model
* @constructor Create an empty Player settings `ViewModel`
*/
class PlayerSettingsViewModel(
private val player: Player,
private val application: Application
private val application: Application,
) : AndroidViewModel(application) {
private val appSettingsRepository = AppSettingsRepository(application)

private val trackSelectionParameters = player.getTrackSelectionParametersAsFlow()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), player.trackSelectionParameters)

Expand All @@ -60,6 +67,9 @@ class PlayerSettingsViewModel(
private val playbackSpeed = player.getPlaybackSpeedAsFlow()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), player.getPlaybackSpeed())

private val appSettings = appSettingsRepository.getAppSettings()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), AppSettings())

/**
* All the available subtitle for the current [player].
*/
Expand Down Expand Up @@ -128,7 +138,15 @@ class PlayerSettingsViewModel(
videoTracks,
trackSelectionParameters,
playbackSpeed,
) { subtitles, audioTracks, videoTracks, trackSelectionParameters, playbackSpeed ->
appSettings,
) { settings ->
val subtitles = settings[SETTING_INDEX_SUBTITLES] as TracksSettingItem?
val audioTracks = settings[SETTING_INDEX_AUDIO_TRACKS] as TracksSettingItem?
val videoTracks = settings[SETTING_INDEX_VIDEO_TRACKS] as TracksSettingItem?
val trackSelectionParameters = settings[SETTING_INDEX_TRACK_SELECTION_PARAMETERS] as TrackSelectionParameters
val playbackSpeed = settings[SETTING_INDEX_PLAYBACK_SPEED] as Float
val appSettings = settings[SETTING_INDEX_APP_SETTINGS] as AppSettings

buildList {
add(
SettingItem(
Expand Down Expand Up @@ -180,6 +198,19 @@ class PlayerSettingsViewModel(
)
)
}

add(
SettingItem(
title = application.getString(R.string.metrics_overlay),
subtitle = if (appSettings.metricsOverlayEnabled) {
application.getString(R.string.metrics_overlay_enabled)
} else {
application.getString(R.string.metrics_overlay_disabled)
},
icon = Icons.Default.Analytics,
destination = SettingsRoutes.MetricsOverlay(appSettings.metricsOverlayEnabled),
)
)
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

Expand Down Expand Up @@ -243,6 +274,17 @@ class PlayerSettingsViewModel(
player.setPlaybackSpeed(playbackSpeed.rawSpeed)
}

/**
* Enable or disable the metrics overlay.
*
* @param enabled
*/
fun setMetricsOverlayEnabled(enabled: Boolean) {
viewModelScope.launch {
appSettingsRepository.setMetricsOverlayEnabled(enabled)
}
}

private fun getTracksSubtitle(
tracks: List<Track>,
disabled: Boolean,
Expand All @@ -252,8 +294,7 @@ class PlayerSettingsViewModel(
} else {
tracks.filter { it.isSelected }
.map { it.format.displayName }
.filter { it != C.LANGUAGE_UNDETERMINED }
.firstOrNull()
.firstOrNull { it != C.LANGUAGE_UNDETERMINED }
}
}

Expand All @@ -267,14 +308,21 @@ class PlayerSettingsViewModel(

private companion object {
private val speeds = floatArrayOf(0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f)

private const val SETTING_INDEX_SUBTITLES = 0
private const val SETTING_INDEX_AUDIO_TRACKS = 1
private const val SETTING_INDEX_VIDEO_TRACKS = 2
private const val SETTING_INDEX_TRACK_SELECTION_PARAMETERS = 3
private const val SETTING_INDEX_PLAYBACK_SPEED = 4
private const val SETTING_INDEX_APP_SETTINGS = 5
}

/**
* Factory
*
* @param player
* @param application
* @constructor Create empty Factory
* @constructor Create an empty Factory
*/
@Suppress("UndocumentedPublicClass")
class Factory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,13 @@ sealed class SettingsRoutes(val route: String) {
* The route for the video track setting.
*/
data object VideoTrack : SettingsRoutes(route = "settings/video_track")

/**
* The route for the metrics overlay setting.
*
* @property enabled Whether the metrics overlay is enabled.
*/
data class MetricsOverlay(
val enabled: Boolean,
) : SettingsRoutes(route = "settings/metrics_overlay")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
package ch.srgssr.pillarbox.demo.shared.ui.settings

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp

/**
* App settings
Expand All @@ -23,13 +21,11 @@ class AppSettings(

/**
* Text size
*
* @property size the [TextUnit].
*/
enum class TextSize(val size: TextUnit) {
Small(8.sp),
Medium(12.sp),
Large(18.sp),
enum class TextSize {
Small,
Medium,
Large,
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package ch.srgssr.pillarbox.demo.shared.ui.settings
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

/**
Expand All @@ -20,6 +22,7 @@ class AppSettingsViewModel(private val appSettingsRepository: AppSettingsReposit
* Current app settings
*/
val currentAppSettings = appSettingsRepository.getAppSettings()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), AppSettings())

/**
* Set metrics overlay enabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
package ch.srgssr.pillarbox.demo.shared.ui.settings

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.text.TextStyle

/**
* Metrics overlay options
*
* @property textColor The [Color] for the text overlay.
* @property textSize The [TextUnit] for the text overlay.
* @property textStyle The [TextStyle] for the text overlay.
*/

data class MetricsOverlayOptions(
val textColor: Color = Color.Yellow,
val textSize: TextUnit = TextUnit.Unspecified,
val textStyle: TextStyle = TextStyle.Default,
)
3 changes: 3 additions & 0 deletions pillarbox-demo-shared/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<string name="settings">Settings</string>
<string name="audio_track">Audio tracks</string>
<string name="video_tracks">Video tracks</string>
<string name="metrics_overlay">Metrics Overlay</string>
<string name="metrics_overlay_enabled">Enabled</string>
<string name="metrics_overlay_disabled">Disabled</string>
<string name="subtitles">Subtitles</string>
<string name="speed">Speed</string>
<string name="speed_normal">Normal</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.core.content.IntentCompat
import androidx.tv.material3.MaterialTheme
import ch.srgssr.pillarbox.demo.shared.data.DemoItem
import ch.srgssr.pillarbox.demo.shared.di.PlayerModule
import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettings
import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettingsRepository
import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettingsViewModel
import ch.srgssr.pillarbox.demo.shared.ui.settings.MetricsOverlayOptions
import ch.srgssr.pillarbox.demo.tv.ui.player.compose.PlayerView
import ch.srgssr.pillarbox.demo.tv.ui.theme.PillarboxTheme
import ch.srgssr.pillarbox.player.PillarboxExoPlayer
Expand All @@ -27,6 +35,9 @@ import ch.srgssr.pillarbox.player.session.PillarboxMediaSession
class PlayerActivity : ComponentActivity() {
private lateinit var player: PillarboxExoPlayer
private lateinit var mediaSession: PillarboxMediaSession
private val appSettingsViewModel by viewModels<AppSettingsViewModel> {
AppSettingsViewModel.Factory(AppSettingsRepository(this))
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -45,9 +56,20 @@ class PlayerActivity : ComponentActivity() {

setContent {
PillarboxTheme {
val appSettings by appSettingsViewModel.currentAppSettings.collectAsState()

PlayerView(
player = player,
modifier = Modifier.fillMaxSize()
modifier = Modifier.fillMaxSize(),
metricsOverlayEnabled = appSettings.metricsOverlayEnabled,
metricsOverlayOptions = MetricsOverlayOptions(
textColor = appSettings.metricsOverlayTextColor.color,
textStyle = when (appSettings.metricsOverlayTextSize) {
AppSettings.TextSize.Small -> MaterialTheme.typography.bodySmall
AppSettings.TextSize.Medium -> MaterialTheme.typography.bodyMedium
AppSettings.TextSize.Large -> MaterialTheme.typography.bodyLarge
},
),
)
}
}
Expand Down
Loading

0 comments on commit 97a5468

Please sign in to comment.