@@ -6,31 +6,37 @@ package ch.srgssr.pillarbox.demo.shared.ui.player.settings
66
77import android.app.Application
88import androidx.compose.material.icons.Icons
9- import androidx.compose.material.icons.filled.Audiotrack
10- import androidx.compose.material.icons.filled.Speed
11- import androidx.compose.material.icons.filled.Subtitles
9+ import androidx.compose.material.icons.filled.ClosedCaption
10+ import androidx.compose.material.icons.filled.RecordVoiceOver
11+ import androidx.compose.material.icons.filled.SlowMotionVideo
12+ import androidx.compose.material.icons.filled.Tune
1213import androidx.lifecycle.AndroidViewModel
1314import androidx.lifecycle.ViewModel
1415import androidx.lifecycle.ViewModelProvider
1516import androidx.lifecycle.viewModelScope
17+ import androidx.media3.common.C
1618import androidx.media3.common.Player
17- import androidx.media3.common.TrackSelectionOverride
18- import androidx.media3.common.Tracks.Group
1919import ch.srgssr.pillarbox.demo.shared.R
20- import ch.srgssr.pillarbox.player.extension.audio
21- import ch.srgssr.pillarbox.player.extension.disableAudioTrack
22- import ch.srgssr.pillarbox.player.extension.disableTextTrack
2320import ch.srgssr.pillarbox.player.extension.displayName
2421import ch.srgssr.pillarbox.player.extension.getPlaybackSpeed
2522import ch.srgssr.pillarbox.player.extension.isAudioTrackDisabled
2623import ch.srgssr.pillarbox.player.extension.isTextTrackDisabled
27- import ch.srgssr.pillarbox.player.extension.setDefaultAudioTrack
28- import ch.srgssr.pillarbox.player.extension.setDefaultTextTrack
29- import ch.srgssr.pillarbox.player.extension.setTrackOverride
30- import ch.srgssr.pillarbox.player.extension.text
24+ import ch.srgssr.pillarbox.player.extension.isVideoTrackDisabled
3125import ch.srgssr.pillarbox.player.getCurrentTracksAsFlow
3226import ch.srgssr.pillarbox.player.getPlaybackSpeedAsFlow
3327import ch.srgssr.pillarbox.player.getTrackSelectionParametersAsFlow
28+ import ch.srgssr.pillarbox.player.tracks.Track
29+ import ch.srgssr.pillarbox.player.tracks.VideoTrack
30+ import ch.srgssr.pillarbox.player.tracks.audioTracks
31+ import ch.srgssr.pillarbox.player.tracks.disableAudioTrack
32+ import ch.srgssr.pillarbox.player.tracks.disableTextTrack
33+ import ch.srgssr.pillarbox.player.tracks.disableVideoTrack
34+ import ch.srgssr.pillarbox.player.tracks.selectTrack
35+ import ch.srgssr.pillarbox.player.tracks.setAutoAudioTrack
36+ import ch.srgssr.pillarbox.player.tracks.setAutoTextTrack
37+ import ch.srgssr.pillarbox.player.tracks.setAutoVideoTrack
38+ import ch.srgssr.pillarbox.player.tracks.textTracks
39+ import ch.srgssr.pillarbox.player.tracks.videoTracks
3440import kotlinx.coroutines.flow.SharingStarted
3541import kotlinx.coroutines.flow.combine
3642import kotlinx.coroutines.flow.map
@@ -54,54 +60,6 @@ class PlayerSettingsViewModel(
5460 private val playbackSpeed = player.getPlaybackSpeedAsFlow()
5561 .stateIn(viewModelScope, SharingStarted .WhileSubscribed (), player.getPlaybackSpeed())
5662
57- /* *
58- * All the available settings for the current [player].
59- */
60- val settings = combine(
61- tracks,
62- trackSelectionParameters,
63- playbackSpeed
64- ) { currentTracks, trackSelectionParameters, playbackSpeed ->
65- buildList {
66- add(
67- SettingItem (
68- title = application.getString(R .string.speed),
69- subtitle = getSpeedLabel(playbackSpeed),
70- icon = Icons .Default .Speed ,
71- destination = SettingsRoutes .PlaybackSpeed
72- )
73- )
74-
75- if (currentTracks.text.isNotEmpty()) {
76- add(
77- SettingItem (
78- title = application.getString(R .string.subtitles),
79- subtitle = getTracksSubtitle(
80- tracks = currentTracks.text,
81- disabled = trackSelectionParameters.isTextTrackDisabled
82- ),
83- icon = Icons .Default .Subtitles ,
84- destination = SettingsRoutes .Subtitles
85- )
86- )
87- }
88-
89- if (currentTracks.audio.isNotEmpty()) {
90- add(
91- SettingItem (
92- title = application.getString(R .string.audio_track),
93- subtitle = getTracksSubtitle(
94- tracks = currentTracks.audio,
95- disabled = trackSelectionParameters.isAudioTrackDisabled
96- ),
97- icon = Icons .Default .Audiotrack ,
98- destination = SettingsRoutes .AudioTrack
99- )
100- )
101- }
102- }
103- }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), emptyList())
104-
10563 /* *
10664 * All the available subtitle for the current [player].
10765 */
@@ -111,7 +69,7 @@ class PlayerSettingsViewModel(
11169 ) { tracks, trackSelectionParameters ->
11270 TracksSettingItem (
11371 title = application.getString(R .string.subtitles),
114- tracks = tracks.text ,
72+ tracks = tracks.textTracks ,
11573 disabled = trackSelectionParameters.isTextTrackDisabled
11674 )
11775 }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), null )
@@ -125,11 +83,29 @@ class PlayerSettingsViewModel(
12583 ) { tracks, trackSelectionParameters ->
12684 TracksSettingItem (
12785 title = application.getString(R .string.audio_track),
128- tracks = tracks.audio ,
86+ tracks = tracks.audioTracks ,
12987 disabled = trackSelectionParameters.isAudioTrackDisabled
13088 )
13189 }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), null )
13290
91+ /* *
92+ * All the available video tracks for the current [player].
93+ */
94+ val videoTracks = combine(
95+ tracks,
96+ trackSelectionParameters,
97+ ) { tracks, trackSelectionParameters ->
98+ TracksSettingItem (
99+ title = application.getString(R .string.video_tracks),
100+ tracks = tracks.videoTracks
101+ .sortedWith(
102+ compareByDescending<VideoTrack > { it.format.height }
103+ .thenByDescending { it.format.bitrate }
104+ ),
105+ disabled = trackSelectionParameters.isVideoTrackDisabled,
106+ )
107+ }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), null )
108+
133109 /* *
134110 * All the available playback speeds for the current [player].
135111 */
@@ -143,11 +119,84 @@ class PlayerSettingsViewModel(
143119 }
144120 }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), emptyList())
145121
122+ /* *
123+ * All the available settings for the current [player].
124+ */
125+ val settings = combine(
126+ subtitles,
127+ audioTracks,
128+ videoTracks,
129+ trackSelectionParameters,
130+ playbackSpeed,
131+ ) { subtitles, audioTracks, videoTracks, trackSelectionParameters, playbackSpeed ->
132+ buildList {
133+ add(
134+ SettingItem (
135+ title = application.getString(R .string.speed),
136+ subtitle = getSpeedLabel(playbackSpeed),
137+ icon = Icons .Default .SlowMotionVideo ,
138+ destination = SettingsRoutes .PlaybackSpeed ,
139+ )
140+ )
141+
142+ if (subtitles != null && subtitles.tracks.isNotEmpty()) {
143+ add(
144+ SettingItem (
145+ title = application.getString(R .string.subtitles),
146+ subtitle = getTracksSubtitle(
147+ tracks = subtitles.tracks,
148+ disabled = trackSelectionParameters.isTextTrackDisabled,
149+ ),
150+ icon = Icons .Default .ClosedCaption ,
151+ destination = SettingsRoutes .Subtitles ,
152+ )
153+ )
154+ }
155+
156+ if (audioTracks != null && audioTracks.tracks.isNotEmpty()) {
157+ add(
158+ SettingItem (
159+ title = application.getString(R .string.audio_track),
160+ subtitle = getTracksSubtitle(
161+ tracks = audioTracks.tracks,
162+ disabled = trackSelectionParameters.isAudioTrackDisabled,
163+ ),
164+ icon = Icons .Default .RecordVoiceOver ,
165+ destination = SettingsRoutes .AudioTrack ,
166+ )
167+ )
168+ }
169+
170+ if (videoTracks != null && videoTracks.tracks.isNotEmpty()) {
171+ add(
172+ SettingItem (
173+ title = application.getString(R .string.video_tracks),
174+ subtitle = getTracksSubtitle(
175+ tracks = videoTracks.tracks,
176+ disabled = trackSelectionParameters.isVideoTrackDisabled,
177+ ),
178+ icon = Icons .Default .Tune ,
179+ destination = SettingsRoutes .VideoTrack ,
180+ )
181+ )
182+ }
183+ }
184+ }.stateIn(viewModelScope, SharingStarted .WhileSubscribed (), emptyList())
185+
186+ /* *
187+ * Select a specific track.
188+ *
189+ * @param track The track to select.
190+ */
191+ fun selectTrack (track : Track ) {
192+ player.selectTrack(track)
193+ }
194+
146195 /* *
147196 * Reset the subtitles.
148197 */
149198 fun resetSubtitles () {
150- player.setDefaultTextTrack (application)
199+ player.setAutoTextTrack (application)
151200 }
152201
153202 /* *
@@ -157,21 +206,11 @@ class PlayerSettingsViewModel(
157206 player.disableTextTrack()
158207 }
159208
160- /* *
161- * Set the subtitles.
162- *
163- * @param group The selected group.
164- * @param trackIndex The index of the track in the provided group.
165- */
166- fun setSubtitle (group : Group , trackIndex : Int ) {
167- player.setTrackOverride(TrackSelectionOverride (group.mediaTrackGroup, trackIndex))
168- }
169-
170209 /* *
171210 * Reset the audio track.
172211 */
173212 fun resetAudioTrack () {
174- player.setDefaultAudioTrack (application)
213+ player.setAutoAudioTrack (application)
175214 }
176215
177216 /* *
@@ -182,13 +221,17 @@ class PlayerSettingsViewModel(
182221 }
183222
184223 /* *
185- * Set the audio track.
186- *
187- * @param group The selected group.
188- * @param trackIndex The index of the track in the provided group.
224+ * Reset the video track.
225+ */
226+ fun resetVideoTrack () {
227+ player.setAutoVideoTrack()
228+ }
229+
230+ /* *
231+ * Disable the video track.
189232 */
190- fun setAudioTrack ( group : Group , trackIndex : Int ) {
191- player.setTrackOverride( TrackSelectionOverride (group.mediaTrackGroup, trackIndex) )
233+ fun disableVideoTrack ( ) {
234+ player.disableVideoTrack( )
192235 }
193236
194237 /* *
@@ -201,22 +244,15 @@ class PlayerSettingsViewModel(
201244 }
202245
203246 private fun getTracksSubtitle (
204- tracks : List <Group >,
205- disabled : Boolean
247+ tracks : List <Track >,
248+ disabled : Boolean ,
206249 ): String? {
207250 return if (disabled) {
208251 application.getString(R .string.disabled)
209252 } else {
210253 tracks.filter { it.isSelected }
211- .flatMap {
212- (0 until it.length).mapNotNull { trackIndex ->
213- if (it.isTrackSelected(trackIndex)) {
214- it.getTrackFormat(trackIndex).displayName
215- } else {
216- null
217- }
218- }
219- }
254+ .map { it.format.displayName }
255+ .filter { it != C .LANGUAGE_UNDETERMINED }
220256 .firstOrNull()
221257 }
222258 }
0 commit comments