Skip to content

Commit

Permalink
195 forced subtitles support (#201)
Browse files Browse the repository at this point in the history
Co-authored-by: Samuel Défago <[email protected]>
  • Loading branch information
StaehliJ and defagos authored Aug 11, 2023
1 parent 9c9504b commit 16c7a49
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 51 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/AppConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import java.util.*
object AppConfig {
const val minSdk = 21
const val targetSdk = 33
const val compileSdk = 33
const val compileSdk = 34

@Suppress("SimpleDateFormat")
fun getBuildDate(): String {
Expand Down
6 changes: 3 additions & 3 deletions buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ object Version {
const val espresso = "3.5.1"
const val lifecycle = "2.6.1"
const val fragment = "1.5.7"
const val navigation = "2.5.3"
const val navigation = "2.7.0"
const val activity = "1.7.2"
const val composeCompiler = "1.5.1"
const val composeUi = "1.4.3"
const val composeMaterial = "1.4.3"
const val composeUi = "1.5.0"
const val composeMaterial = "1.5.0"
const val detetk = "1.22.0"

/*
Expand Down
4 changes: 2 additions & 2 deletions pillarbox-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ dependencies {
implementation(Dependencies.Compose.activity)
implementation(Dependencies.Compose.navigation)
implementation(Dependencies.Compose.viewmodel)
implementation("com.google.accompanist:accompanist-systemuicontroller:0.30.1")
implementation("com.google.accompanist:accompanist-navigation-material:0.30.1")
implementation("com.google.accompanist:accompanist-systemuicontroller:0.33.0-alpha")
implementation("com.google.accompanist:accompanist-navigation-material:0.33.0-alpha")

// Integration layer
val dataProviderVersion = "0.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package ch.srgssr.pillarbox.demo.ui.player.settings

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.foundation.clickable
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
Expand Down Expand Up @@ -68,7 +69,15 @@ fun PlaybackSettingsContent(
val settingsViewModel: PlayerSettingsViewModel = viewModel(factory = PlayerSettingsViewModel.Factory(player))
val currentPlaybackSpeed = settingsViewModel.playbackSpeed.collectAsState().value
NavHost(navController = navController, startDestination = SettingDestination.Home.route) {
composable(route = SettingDestination.Home.route) {
composable(
route = SettingDestination.Home.route,
exitTransition = {
slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Down)
},
enterTransition = {
slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Up)
}
) {
val hasAudios = settingsViewModel.hasAudio.collectAsState(initial = false)
val hasSubtitles = settingsViewModel.hasSubtitles.collectAsState(initial = false)
SettingsHome(
Expand All @@ -82,13 +91,29 @@ fun PlaybackSettingsContent(
},
)
}
composable(route = SettingDestination.PlaybackSpeed.route) {
composable(
route = SettingDestination.PlaybackSpeed.route,
exitTransition = {
slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Down)
},
enterTransition = {
slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Up)
}
) {
PlaybackSpeedSettings(currentSpeed = currentPlaybackSpeed, onSpeedSelected = {
player.setPlaybackSpeed(it)
onDismissState()
})
}
composable(route = SettingDestination.Subtitles.route) {
composable(
route = SettingDestination.Subtitles.route,
exitTransition = {
slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Down)
},
enterTransition = {
slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Up)
}
) {
val textTrackState = settingsViewModel.textTracks.collectAsState()
val textTrackSelection = settingsViewModel.trackSelectionParameters.collectAsState()
val disabled = textTrackSelection.value.isTextTrackDisabled
Expand All @@ -110,7 +135,15 @@ fun PlaybackSettingsContent(
onDismissState()
}
}
composable(route = SettingDestination.Audios.route) {
composable(
route = SettingDestination.Audios.route,
exitTransition = {
slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Down)
},
enterTransition = {
slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Up)
}
) {
val audioTracks = settingsViewModel.audioTracks.collectAsState()
val trackSelectionParametersState = settingsViewModel.trackSelectionParameters.collectAsState()
val disabled = trackSelectionParametersState.value.isAudioTrackDisabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import androidx.media3.common.Format
import androidx.media3.common.TrackGroup
import androidx.media3.common.Tracks
import ch.srgssr.pillarbox.demo.ui.theme.PillarboxTheme
import ch.srgssr.pillarbox.player.extension.hasRole
import ch.srgssr.pillarbox.player.extension.roleString
import ch.srgssr.pillarbox.player.extension.displayName
import ch.srgssr.pillarbox.player.extension.hasAccessibilityRoles

/**
* Track selection settings
Expand Down Expand Up @@ -74,22 +74,27 @@ fun TrackSelectionSettings(
when (group.type) {
C.TRACK_TYPE_AUDIO -> {
val str = StringBuilder()
str.append("${format.label} / ${format.language}")
str.append(format.displayName)
if (format.bitrate > Format.NO_VALUE) {
str.append(" @${format.bitrate} bit/sec")
}
Text(text = str.toString())
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = str.toString())
if (format.hasAccessibilityRoles()) {
Icon(imageVector = Icons.Filled.HearingDisabled, contentDescription = "AD")
}
}
}

else -> {
if (format.hasRole(C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND.or(C.ROLE_FLAG_TRANSCRIBES_DIALOG))) {
if (format.hasAccessibilityRoles()) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "${format.label} / ${format.language}")
Text(text = format.displayName)
Spacer(modifier = Modifier.width(12.dp))
Icon(imageVector = Icons.Default.HearingDisabled, contentDescription = "Hearing disabled")
}
} else {
Text(text = "${format.label} / ${format.language} ${format.roleString()}")
Text(text = format.displayName)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ import ch.srgssr.pillarbox.ui.ScaleMode
@Composable
fun OptimizedStory(storyViewModel: StoryViewModel = viewModel()) {
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
val pagerState = rememberPagerState()

val pagerState = rememberPagerState() {
storyViewModel.playlist.items.size
}
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
Expand All @@ -53,16 +56,15 @@ fun OptimizedStory(storyViewModel: StoryViewModel = viewModel()) {
val playlist = storyViewModel.playlist.items
HorizontalPager(
modifier = Modifier.fillMaxHeight(),
beyondBoundsPageCount = 0,
key = { page -> playlist[page].uri },
flingBehavior = PagerDefaults.flingBehavior(
state = pagerState,
pagerSnapDistance = PagerSnapDistance.atMost(0),
snapAnimationSpec = spring(stiffness = Spring.StiffnessHigh)
),
beyondBoundsPageCount = 0,
pageCount = playlist.size,
state = pagerState,
pageSpacing = 1.dp
pageSpacing = 1.dp,
state = pagerState
) { page ->
// When flinging -> may "load" more that 3 pages
val currentPage = pagerState.currentPage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ fun SimpleStory() {
Playlist.VideoUrls
}

val pagerState = rememberPagerState()
val pagerState = rememberPagerState() { playlist.items.size }
HorizontalPager(
modifier = Modifier.fillMaxHeight(),
key = { page -> playlist.items[page].uri },
pageCount = playlist.items.size,
state = pagerState
) { page ->
SimpleStoryPlayer(demoItem = playlist.items[page], isPlaying = pagerState.currentPage == page)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,20 +282,21 @@ fun Player.getAspectRatioAsFlow(defaultAspectRatio: Float): Flow<Float> = videoS
/**
* Get track selection parameters as flow [Player.getTrackSelectionParameters]
*/
fun Player.getTrackSelectionParametersAsFlow() = callbackFlow {
fun Player.getTrackSelectionParametersAsFlow(): Flow<TrackSelectionParameters> = callbackFlow {
val listener = object : Player.Listener {
override fun onTrackSelectionParametersChanged(parameters: TrackSelectionParameters) {
trySend(parameters)
}
}

trySend(trackSelectionParameters)
addPlayerListener(player = this@getTrackSelectionParametersAsFlow, listener)
}

/**
* Get current tracks as flow [Player.getCurrentTracks]
*/
fun Player.getCurrentTracksAsFlow() = callbackFlow {
fun Player.getCurrentTracksAsFlow(): Flow<Tracks> = callbackFlow {
val listener = object : Player.Listener {
override fun onTracksChanged(tracks: Tracks) {
trySend(tracks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.media3.common.C.RoleFlags
import androidx.media3.common.C.SelectionFlags
import androidx.media3.common.Format
import androidx.media3.common.VideoSize
import java.util.Locale

/**
* Check if [Format.roleFlags] contains [role]
Expand All @@ -28,6 +29,13 @@ fun Format.hasSelection(selection: @SelectionFlags Int): Boolean {
return selectionFlags and selection != 0
}

/**
* Is forced
*/
fun Format.isForced(): Boolean {
return hasSelection(C.SELECTION_FLAG_FORCED)
}

/**
* Video size of the format. [VideoSize.UNKNOWN] if no video size provided.
*/
Expand Down Expand Up @@ -109,3 +117,25 @@ fun Format.roleString(): String {
}
return roleFlags.joinToString(",")
}

/**
* Has accessibility roles
*/
fun Format.hasAccessibilityRoles(): Boolean {
return hasRole(C.ROLE_FLAG_DESCRIBES_VIDEO or C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND)
}

/**
* Returns a locale for the specified IETF BCP 47 [Format.language] tag string.
*
* @return null if not applicable.
*/
fun Format.getLocale(): Locale? {
return language?.let { Locale.forLanguageTag(language) }
}

/**
* Display name
*/
val Format.displayName: String
get() = getLocale()?.let { it.displayName } ?: label ?: C.LANGUAGE_UNDETERMINED
Loading

0 comments on commit 16c7a49

Please sign in to comment.