Skip to content

Commit

Permalink
Add a setting in the demos to change the video quality
Browse files Browse the repository at this point in the history
  • Loading branch information
MGaetan89 committed Apr 12, 2024
1 parent d4c7b33 commit 0b5d72b
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ 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.Audiotrack
import androidx.compose.material.icons.filled.Speed
import androidx.compose.material.icons.filled.Subtitles
import androidx.compose.material.icons.filled.ClosedCaption
import androidx.compose.material.icons.filled.RecordVoiceOver
import androidx.compose.material.icons.filled.SlowMotionVideo
import androidx.compose.material.icons.filled.Tune
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
Expand All @@ -19,17 +20,22 @@ import ch.srgssr.pillarbox.player.extension.displayName
import ch.srgssr.pillarbox.player.extension.getPlaybackSpeed
import ch.srgssr.pillarbox.player.extension.isAudioTrackDisabled
import ch.srgssr.pillarbox.player.extension.isTextTrackDisabled
import ch.srgssr.pillarbox.player.extension.isVideoTrackDisabled
import ch.srgssr.pillarbox.player.getCurrentTracksAsFlow
import ch.srgssr.pillarbox.player.getPlaybackSpeedAsFlow
import ch.srgssr.pillarbox.player.getTrackSelectionParametersAsFlow
import ch.srgssr.pillarbox.player.tracks.Track
import ch.srgssr.pillarbox.player.tracks.VideoTrack
import ch.srgssr.pillarbox.player.tracks.audioTracks
import ch.srgssr.pillarbox.player.tracks.disableAudioTrack
import ch.srgssr.pillarbox.player.tracks.disableTextTrack
import ch.srgssr.pillarbox.player.tracks.disableVideoTrack
import ch.srgssr.pillarbox.player.tracks.selectTrack
import ch.srgssr.pillarbox.player.tracks.setAutoAudioTrack
import ch.srgssr.pillarbox.player.tracks.setAutoTextTrack
import ch.srgssr.pillarbox.player.tracks.setAutoVideoTrack
import ch.srgssr.pillarbox.player.tracks.textTracks
import ch.srgssr.pillarbox.player.tracks.videoTracks
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
Expand All @@ -53,57 +59,6 @@ class PlayerSettingsViewModel(
private val playbackSpeed = player.getPlaybackSpeedAsFlow()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), player.getPlaybackSpeed())

/**
* All the available settings for the current [player].
*/
val settings = combine(
tracks,
trackSelectionParameters,
playbackSpeed
) { currentTracks, trackSelectionParameters, playbackSpeed ->
buildList {
val textTracks = currentTracks.textTracks
val audioTracks = currentTracks.audioTracks

add(
SettingItem(
title = application.getString(R.string.speed),
subtitle = getSpeedLabel(playbackSpeed),
icon = Icons.Default.Speed,
destination = SettingsRoutes.PlaybackSpeed
)
)

if (textTracks.isNotEmpty()) {
add(
SettingItem(
title = application.getString(R.string.subtitles),
subtitle = getTracksSubtitle(
tracks = textTracks,
disabled = trackSelectionParameters.isTextTrackDisabled
),
icon = Icons.Default.Subtitles,
destination = SettingsRoutes.Subtitles
)
)
}

if (audioTracks.isNotEmpty()) {
add(
SettingItem(
title = application.getString(R.string.audio_track),
subtitle = getTracksSubtitle(
tracks = audioTracks,
disabled = trackSelectionParameters.isAudioTrackDisabled
),
icon = Icons.Default.Audiotrack,
destination = SettingsRoutes.AudioTrack
)
)
}
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

/**
* All the available subtitle for the current [player].
*/
Expand Down Expand Up @@ -132,6 +87,22 @@ class PlayerSettingsViewModel(
)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)

/**
* All the available video qualities for the current [player].
*/
val videoQualities = combine(
tracks,
trackSelectionParameters,
) { tracks, trackSelectionParameters ->
TracksSettingItem(
title = application.getString(R.string.quality),
tracks = tracks.videoTracks
.distinctBy { it.format.height }
.sortedByDescending { it.format.height },
disabled = trackSelectionParameters.isVideoTrackDisabled,
)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)

/**
* All the available playback speeds for the current [player].
*/
Expand All @@ -145,6 +116,79 @@ class PlayerSettingsViewModel(
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

/**
* All the available settings for the current [player].
*/
val settings = combine(
subtitles,
audioTracks,
videoQualities,
trackSelectionParameters,
playbackSpeed,
) { subtitles, audioTracks, videoQualities, trackSelectionParameters, playbackSpeed ->
buildList {
add(
SettingItem(
title = application.getString(R.string.speed),
subtitle = getSpeedLabel(playbackSpeed),
icon = Icons.Default.SlowMotionVideo,
destination = SettingsRoutes.PlaybackSpeed,
)
)

if (subtitles != null && subtitles.tracks.isNotEmpty()) {
add(
SettingItem(
title = application.getString(R.string.subtitles),
subtitle = getTracksSubtitle(
tracks = subtitles.tracks,
disabled = trackSelectionParameters.isTextTrackDisabled,
),
icon = Icons.Default.ClosedCaption,
destination = SettingsRoutes.Subtitles,
)
)
}

if (audioTracks != null && audioTracks.tracks.isNotEmpty()) {
add(
SettingItem(
title = application.getString(R.string.audio_track),
subtitle = getTracksSubtitle(
tracks = audioTracks.tracks,
disabled = trackSelectionParameters.isAudioTrackDisabled,
),
icon = Icons.Default.RecordVoiceOver,
destination = SettingsRoutes.AudioTrack,
)
)
}

if (videoQualities != null && videoQualities.tracks.isNotEmpty()) {
add(
SettingItem(
title = application.getString(R.string.quality),
subtitle = getTracksSubtitle(
tracks = videoQualities.tracks,
disabled = trackSelectionParameters.isVideoTrackDisabled,
),
icon = Icons.Default.Tune,
destination = SettingsRoutes.VideoQuality,
)
)
}
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

/**
* Select a specific track.
*
* @param track The track to select.
*/
fun selectTrack(track: Track) {
player.selectTrack(track)
}

/**
* Reset the subtitles.
*/
Expand All @@ -159,15 +203,6 @@ class PlayerSettingsViewModel(
player.disableTextTrack()
}

/**
* Select a specific track.
*
* @param track The track to select.
*/
fun selectTrack(track: Track) {
player.selectTrack(track)
}

/**
* Reset the audio track.
*/
Expand All @@ -182,6 +217,20 @@ class PlayerSettingsViewModel(
player.disableAudioTrack()
}

/**
* Reset the video track.
*/
fun resetVideoTrack() {
player.setAutoVideoTrack(application)
}

/**
* Disable the video track.
*/
fun disableVideoTrack() {
player.disableVideoTrack()
}

/**
* Set the playback speed.
*
Expand All @@ -199,7 +248,13 @@ class PlayerSettingsViewModel(
application.getString(R.string.disabled)
} else {
tracks.filter { it.isSelected }
.map { it.format.displayName }
.map {
if (it is VideoTrack) {
it.format.height.toString() + "p"
} else {
it.format.displayName
}
}
.firstOrNull()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ sealed class SettingsRoutes(val route: String) {
* The route for the audio track setting.
*/
data object AudioTrack : SettingsRoutes(route = "settings/audio_track")

/**
* The route for the video quality setting.
*/
data object VideoQuality : SettingsRoutes(route = "settings/video_quality")
}
1 change: 1 addition & 0 deletions pillarbox-demo-shared/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<string name="duration"><xliff:g example="15" id="duration">%1$d</xliff:g> min</string>
<string name="settings">Settings</string>
<string name="audio_track">Audio track</string>
<string name="quality">Quality</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 @@ -58,6 +58,7 @@ import ch.srgssr.pillarbox.demo.tv.ui.theme.paddings
import ch.srgssr.pillarbox.player.extension.displayName
import ch.srgssr.pillarbox.player.extension.hasAccessibilityRoles
import ch.srgssr.pillarbox.player.tracks.Track
import ch.srgssr.pillarbox.player.tracks.VideoTrack

/**
* Drawer used to display a player's settings.
Expand Down Expand Up @@ -180,6 +181,19 @@ private fun NavigationDrawerScope.NavigationDrawerNavHost(
}
}

composable(SettingsRoutes.VideoQuality.route) {
val videoQualities by settingsViewModel.videoQualities.collectAsState()

videoQualities?.let {
TracksSetting(
tracksSetting = it,
onResetClick = settingsViewModel::resetVideoTrack,
onDisabledClick = settingsViewModel::disableVideoTrack,
onTrackClick = settingsViewModel::selectTrack,
)
}
}

composable(SettingsRoutes.Subtitles.route) {
val subtitles by settingsViewModel.subtitles.collectAsState()

Expand Down Expand Up @@ -330,17 +344,21 @@ private fun NavigationDrawerScope.TracksSetting(
},
content = {
val format = track.format
val label = buildString {
append(format.displayName)
val label = if (track is VideoTrack) {
format.height.toString() + "p"
} else {
buildString {
append(format.displayName)

if (format.bitrate > Format.NO_VALUE) {
append(" @")
append(format.bitrate)
append(" bit/sec")
}
if (format.bitrate > Format.NO_VALUE) {
append(" @")
append(format.bitrate)
append(" bit/sec")
}

if (format.hasAccessibilityRoles()) {
append(" (AD)")
if (format.hasAccessibilityRoles()) {
append(" (AD)")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fun PlaybackSettingsContent(player: Player) {
},
)
}

composable(
route = SettingsRoutes.PlaybackSpeed.route,
exitTransition = {
Expand All @@ -75,6 +76,7 @@ fun PlaybackSettingsContent(player: Player) {
onSpeedSelected = settingsViewModel::setPlaybackSpeed
)
}

composable(
route = SettingsRoutes.Subtitles.route,
exitTransition = {
Expand All @@ -94,6 +96,7 @@ fun PlaybackSettingsContent(player: Player) {
)
}
}

composable(
route = SettingsRoutes.AudioTrack.route,
exitTransition = {
Expand All @@ -113,6 +116,26 @@ fun PlaybackSettingsContent(player: Player) {
)
}
}

composable(
route = SettingsRoutes.VideoQuality.route,
exitTransition = {
slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Down)
},
enterTransition = {
slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Up)
}
) {
val videoQualities by settingsViewModel.videoQualities.collectAsState()
videoQualities?.let {
TrackSelectionSettings(
tracksSetting = it,
onResetClick = settingsViewModel::resetVideoTrack,
onDisabledClick = settingsViewModel::disableVideoTrack,
onTrackClick = settingsViewModel::selectTrack,
)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import ch.srgssr.pillarbox.player.extension.hasAccessibilityRoles
import ch.srgssr.pillarbox.player.tracks.AudioTrack
import ch.srgssr.pillarbox.player.tracks.TextTrack
import ch.srgssr.pillarbox.player.tracks.Track
import ch.srgssr.pillarbox.player.tracks.VideoTrack

/**
* Track selection settings
Expand Down Expand Up @@ -104,6 +105,10 @@ fun TrackSelectionSettings(
}
}

is VideoTrack -> {
Text(text = format.height.toString() + "p")
}

else -> {
if (format.hasAccessibilityRoles()) {
Row(verticalAlignment = Alignment.CenterVertically) {
Expand Down
Loading

0 comments on commit 0b5d72b

Please sign in to comment.