-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move
PlayerSettingsViewModel
to pillarbox-demo-shared
- Loading branch information
Showing
12 changed files
with
503 additions
and
431 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
.../src/main/java/ch/srgssr/pillarbox/demo/shared/ui/player/settings/PlaybackSpeedSetting.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.shared.ui.player.settings | ||
|
||
/** | ||
* A possible playback speed value. | ||
*/ | ||
data class PlaybackSpeedSetting( | ||
/** | ||
* The formatted speed. | ||
*/ | ||
val speed: String, | ||
|
||
/** | ||
* The speed as [Float]. | ||
*/ | ||
val rawSpeed: Float, | ||
|
||
/** | ||
* `true` if this speed is selected, `false` otherwise. | ||
*/ | ||
val isSelected: Boolean | ||
) |
251 changes: 251 additions & 0 deletions
251
...c/main/java/ch/srgssr/pillarbox/demo/shared/ui/player/settings/PlayerSettingsViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
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.lifecycle.AndroidViewModel | ||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.ViewModelProvider | ||
import androidx.lifecycle.viewModelScope | ||
import androidx.media3.common.Player | ||
import androidx.media3.common.TrackSelectionOverride | ||
import androidx.media3.common.Tracks.Group | ||
import ch.srgssr.pillarbox.demo.shared.R | ||
import ch.srgssr.pillarbox.player.extension.audio | ||
import ch.srgssr.pillarbox.player.extension.disableAudioTrack | ||
import ch.srgssr.pillarbox.player.extension.disableTextTrack | ||
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.setDefaultAudioTrack | ||
import ch.srgssr.pillarbox.player.extension.setDefaultTextTrack | ||
import ch.srgssr.pillarbox.player.extension.setTrackOverride | ||
import ch.srgssr.pillarbox.player.extension.text | ||
import ch.srgssr.pillarbox.player.getCurrentTracksAsFlow | ||
import ch.srgssr.pillarbox.player.getPlaybackSpeedAsFlow | ||
import ch.srgssr.pillarbox.player.getTrackSelectionParametersAsFlow | ||
import kotlinx.coroutines.flow.SharingStarted | ||
import kotlinx.coroutines.flow.combine | ||
import kotlinx.coroutines.flow.map | ||
import kotlinx.coroutines.flow.stateIn | ||
|
||
/** | ||
* Player settings view model | ||
* | ||
* @constructor Create empty Player settings view model | ||
*/ | ||
class PlayerSettingsViewModel( | ||
private val player: Player, | ||
private val application: Application | ||
) : AndroidViewModel(application) { | ||
private val trackSelectionParameters = player.getTrackSelectionParametersAsFlow() | ||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), player.trackSelectionParameters) | ||
|
||
private val tracks = player.getCurrentTracksAsFlow() | ||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), player.currentTracks) | ||
|
||
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 { | ||
add( | ||
SettingItem( | ||
title = application.getString(R.string.speed), | ||
subtitle = getSpeedLabel(playbackSpeed), | ||
icon = Icons.Default.Speed, | ||
destination = SettingsRoutes.PlaybackSpeed | ||
) | ||
) | ||
|
||
if (currentTracks.text.isNotEmpty()) { | ||
add( | ||
SettingItem( | ||
title = application.getString(R.string.subtitles), | ||
subtitle = getTracksSubtitle( | ||
tracks = currentTracks.text, | ||
disabled = trackSelectionParameters.isTextTrackDisabled | ||
), | ||
icon = Icons.Default.Subtitles, | ||
destination = SettingsRoutes.Subtitles | ||
) | ||
) | ||
} | ||
|
||
if (currentTracks.audio.isNotEmpty()) { | ||
add( | ||
SettingItem( | ||
title = application.getString(R.string.audio_track), | ||
subtitle = getTracksSubtitle( | ||
tracks = currentTracks.audio, | ||
disabled = trackSelectionParameters.isAudioTrackDisabled | ||
), | ||
icon = Icons.Default.Audiotrack, | ||
destination = SettingsRoutes.AudioTrack | ||
) | ||
) | ||
} | ||
} | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) | ||
|
||
/** | ||
* All the available subtitle for the current [player]. | ||
*/ | ||
val subtitles = combine( | ||
tracks, | ||
trackSelectionParameters | ||
) { tracks, trackSelectionParameters -> | ||
TracksSettingItem( | ||
title = application.getString(R.string.subtitles), | ||
tracks = tracks.text, | ||
disabled = trackSelectionParameters.isTextTrackDisabled | ||
) | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TracksSettingItem.empty) | ||
|
||
/** | ||
* All the available audio tracks for the current [player]. | ||
*/ | ||
val audioTracks = combine( | ||
tracks, | ||
trackSelectionParameters | ||
) { tracks, trackSelectionParameters -> | ||
TracksSettingItem( | ||
title = application.getString(R.string.audio_track), | ||
tracks = tracks.audio, | ||
disabled = trackSelectionParameters.isAudioTrackDisabled | ||
) | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TracksSettingItem.empty) | ||
|
||
/** | ||
* All the available playback speeds for the current [player]. | ||
*/ | ||
val playbackSpeeds = playbackSpeed.map { playbackSpeed -> | ||
@Suppress("MagicNumber") | ||
val speeds = listOf(0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f) | ||
|
||
speeds.map { speed -> | ||
PlaybackSpeedSetting( | ||
speed = getSpeedLabel(speed), | ||
rawSpeed = speed, | ||
isSelected = speed == playbackSpeed | ||
) | ||
} | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) | ||
|
||
/** | ||
* Reset the subtitles. | ||
*/ | ||
fun resetSubtitles() { | ||
player.setDefaultTextTrack(application) | ||
} | ||
|
||
/** | ||
* Disable the subtitles. | ||
*/ | ||
fun disableSubtitles() { | ||
player.disableTextTrack() | ||
} | ||
|
||
/** | ||
* Set the subtitles. | ||
* | ||
* @param group The selected group. | ||
* @param trackIndex The index of the track in the provided group. | ||
*/ | ||
fun setSubtitle(group: Group, trackIndex: Int) { | ||
player.setTrackOverride(TrackSelectionOverride(group.mediaTrackGroup, trackIndex)) | ||
} | ||
|
||
/** | ||
* Reset the audio track. | ||
*/ | ||
fun resetAudioTrack() { | ||
player.setDefaultAudioTrack(application) | ||
} | ||
|
||
/** | ||
* Disable the audio track. | ||
*/ | ||
fun disableAudioTrack() { | ||
player.disableAudioTrack() | ||
} | ||
|
||
/** | ||
* Set the audio track. | ||
* | ||
* @param group The selected group. | ||
* @param trackIndex The index of the track in the provided group. | ||
*/ | ||
fun setAudioTrack(group: Group, trackIndex: Int) { | ||
player.setTrackOverride(TrackSelectionOverride(group.mediaTrackGroup, trackIndex)) | ||
} | ||
|
||
/** | ||
* Set the playback speed. | ||
* | ||
* @param playbackSpeed The selected playback speed. | ||
*/ | ||
fun setPlaybackSpeed(playbackSpeed: PlaybackSpeedSetting) { | ||
player.setPlaybackSpeed(playbackSpeed.rawSpeed) | ||
} | ||
|
||
private fun getTracksSubtitle( | ||
tracks: List<Group>, | ||
disabled: Boolean | ||
): String? { | ||
return if (disabled) { | ||
application.getString(R.string.disabled) | ||
} else { | ||
tracks.filter { it.isSelected } | ||
.flatMap { | ||
(0 until it.length).mapNotNull { trackIndex -> | ||
if (it.isTrackSelected(trackIndex)) { | ||
it.getTrackFormat(trackIndex).displayName | ||
} else { | ||
null | ||
} | ||
} | ||
} | ||
.firstOrNull() | ||
} | ||
} | ||
|
||
private fun getSpeedLabel(speed: Float): String { | ||
return if (speed == 1f) { | ||
application.getString(R.string.speed_normal) | ||
} else { | ||
application.getString(R.string.speed_value, speed.toString()) | ||
} | ||
} | ||
|
||
/** | ||
* Factory | ||
* | ||
* @param player | ||
* @param application | ||
* @constructor Create empty Factory | ||
*/ | ||
@Suppress("UndocumentedPublicClass") | ||
class Factory( | ||
private val player: Player, | ||
private val application: Application | ||
) : ViewModelProvider.NewInstanceFactory() { | ||
override fun <T : ViewModel> create(modelClass: Class<T>): T { | ||
return PlayerSettingsViewModel(player, application) as T | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...mo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/player/settings/SettingItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.shared.ui.player.settings | ||
|
||
import androidx.compose.ui.graphics.vector.ImageVector | ||
|
||
/** | ||
* Represent a setting item. | ||
*/ | ||
data class SettingItem( | ||
/** | ||
* The title of the setting. | ||
*/ | ||
val title: String, | ||
|
||
/** | ||
* The optional subtitle of the setting. | ||
*/ | ||
val subtitle: String?, | ||
|
||
/** | ||
* The icon of the setting. | ||
*/ | ||
val icon: ImageVector, | ||
|
||
/** | ||
* The route of the setting. | ||
*/ | ||
val destination: SettingsRoutes | ||
) |
32 changes: 32 additions & 0 deletions
32
...shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/player/settings/SettingsRoutes.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.shared.ui.player.settings | ||
|
||
/** | ||
* All the routes used in the player's settings. | ||
* | ||
* @property route The route of the setting. | ||
*/ | ||
sealed class SettingsRoutes(val route: String) { | ||
/** | ||
* The route for the main screen of the settings. | ||
*/ | ||
data object Settings : SettingsRoutes(route = "settings") | ||
|
||
/** | ||
* The route for the playback speed setting. | ||
*/ | ||
data object PlaybackSpeed : SettingsRoutes(route = "settings/playback_speed") | ||
|
||
/** | ||
* The route for the subtitles setting. | ||
*/ | ||
data object Subtitles : SettingsRoutes(route = "settings/subtitles") | ||
|
||
/** | ||
* The route for the audio track setting. | ||
*/ | ||
data object AudioTrack : SettingsRoutes(route = "settings/audio_track") | ||
} |
38 changes: 38 additions & 0 deletions
38
...red/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/player/settings/TracksSettingItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.shared.ui.player.settings | ||
|
||
import androidx.media3.common.Tracks.Group | ||
|
||
/** | ||
* The setting for a specific kind a track (audio/text/video). | ||
*/ | ||
data class TracksSettingItem( | ||
/** | ||
* The title of the setting. | ||
*/ | ||
val title: String, | ||
|
||
/** | ||
* The list of possible tracks. | ||
*/ | ||
val tracks: List<Group>, | ||
|
||
/** | ||
* `true` if this kind of tracks is disabled, `false` otherwise. | ||
*/ | ||
val disabled: Boolean | ||
) { | ||
companion object { | ||
/** | ||
* Default tracks setting, which has no title, and no values. | ||
*/ | ||
val empty = TracksSettingItem( | ||
title = "", | ||
tracks = emptyList(), | ||
disabled = true | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.