feat(phone): use custom track selection dialog for default player

Use media3 track type instead of mpv track type
Simplify track selection dialog
This commit is contained in:
Jarne Demeulemeester 2024-01-01 12:23:53 +01:00
parent db5eab1ab2
commit 55427036b2
No known key found for this signature in database
GPG key ID: 1E5C6AFBD622E9F5
5 changed files with 49 additions and 128 deletions

View file

@ -27,18 +27,15 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.media3.common.C
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.DefaultTimeBar
import androidx.media3.ui.PlayerView
import androidx.media3.ui.TrackSelectionDialogBuilder
import androidx.navigation.navArgs
import dagger.hilt.android.AndroidEntryPoint
import dev.jdtech.jellyfin.databinding.ActivityPlayerBinding
import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment
import dev.jdtech.jellyfin.dialogs.TrackSelectionDialogFragment
import dev.jdtech.jellyfin.mpv.MPVPlayer
import dev.jdtech.jellyfin.mpv.TrackType
import dev.jdtech.jellyfin.utils.PlayerGestureHelper
import dev.jdtech.jellyfin.utils.PreviewScrubListener
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
@ -46,7 +43,6 @@ import dev.jdtech.jellyfin.viewmodels.PlayerEvents
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import dev.jdtech.jellyfin.player.video.R as PlayerVideoR
var isControlsLocked: Boolean = false
@ -201,38 +197,10 @@ class PlayerActivity : BasePlayerActivity() {
}
audioButton.setOnClickListener {
when (viewModel.player) {
is MPVPlayer -> {
TrackSelectionDialogFragment(TrackType.AUDIO, viewModel).show(
supportFragmentManager,
"trackselectiondialog",
)
}
is ExoPlayer -> {
val mappedTrackInfo =
viewModel.trackSelector.currentMappedTrackInfo ?: return@setOnClickListener
var audioRenderer: Int? = null
for (i in 0 until mappedTrackInfo.rendererCount) {
if (isRendererType(mappedTrackInfo, i, C.TRACK_TYPE_AUDIO)) {
audioRenderer = i
}
}
if (audioRenderer == null) return@setOnClickListener
val trackSelectionDialogBuilder = TrackSelectionDialogBuilder(
this,
resources.getString(PlayerVideoR.string.select_audio_track),
viewModel.player,
C.TRACK_TYPE_AUDIO,
)
trackSelectionDialogBuilder.setShowDisableOption(true)
val trackSelectionDialog = trackSelectionDialogBuilder.build()
trackSelectionDialog.show()
}
}
TrackSelectionDialogFragment(C.TRACK_TYPE_AUDIO, viewModel).show(
supportFragmentManager,
"trackselectiondialog",
)
}
val exoPlayerControlView = findViewById<FrameLayout>(R.id.player_controls)
@ -253,38 +221,10 @@ class PlayerActivity : BasePlayerActivity() {
}
subtitleButton.setOnClickListener {
when (viewModel.player) {
is MPVPlayer -> {
TrackSelectionDialogFragment(TrackType.SUBTITLE, viewModel).show(
supportFragmentManager,
"trackselectiondialog",
)
}
is ExoPlayer -> {
val mappedTrackInfo =
viewModel.trackSelector.currentMappedTrackInfo ?: return@setOnClickListener
var subtitleRenderer: Int? = null
for (i in 0 until mappedTrackInfo.rendererCount) {
if (isRendererType(mappedTrackInfo, i, C.TRACK_TYPE_TEXT)) {
subtitleRenderer = i
}
}
if (subtitleRenderer == null) return@setOnClickListener
val trackSelectionDialogBuilder = TrackSelectionDialogBuilder(
this,
resources.getString(PlayerVideoR.string.select_subtile_track),
viewModel.player,
C.TRACK_TYPE_TEXT,
)
trackSelectionDialogBuilder.setShowDisableOption(true)
val trackSelectionDialog = trackSelectionDialogBuilder.build()
trackSelectionDialog.show()
}
}
TrackSelectionDialogFragment(C.TRACK_TYPE_TEXT, viewModel).show(
supportFragmentManager,
"trackselectiondialog",
)
}
speedButton.setOnClickListener {

View file

@ -124,7 +124,7 @@ fun PlayerScreen(
val trackType = result.value.trackType
val index = result.value.index
if (result.value.index == -1) {
if (index == -1) {
viewModel.player.trackSelectionParameters = viewModel.player.trackSelectionParameters
.buildUpon()
.clearOverridesOfType(trackType)

View file

@ -6,56 +6,36 @@ import androidx.fragment.app.DialogFragment
import androidx.media3.common.C
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.jdtech.jellyfin.getTrackNames
import dev.jdtech.jellyfin.mpv.TrackType
import dev.jdtech.jellyfin.player.video.R
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
import java.lang.IllegalStateException
class TrackSelectionDialogFragment(
private val type: TrackType,
private val type: @C.TrackType Int,
private val viewModel: PlayerActivityViewModel,
) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
when (type) {
TrackType.AUDIO -> {
return activity?.let { activity ->
val builder = MaterialAlertDialogBuilder(activity)
val tracksGroups = viewModel.player.currentTracks.groups.filter { it.type == C.TRACK_TYPE_AUDIO }
builder.setTitle(getString(R.string.select_audio_track))
.setSingleChoiceItems(
arrayOf(getString(R.string.none)) + tracksGroups.getTrackNames(), // Add "None" at the top of the list
tracksGroups.indexOfFirst { it.isSelected } + 1, // Add 1 to the index to account for the "None" item
) { dialog, which ->
viewModel.switchToTrack(
TrackType.AUDIO,
which - 1, // Minus 1 to get the correct group without the "None" item. "None" becomes -1
)
dialog.dismiss()
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
TrackType.SUBTITLE -> {
return activity?.let { activity ->
val builder = MaterialAlertDialogBuilder(activity)
val tracksGroups = viewModel.player.currentTracks.groups.filter { it.type == C.TRACK_TYPE_TEXT }
builder.setTitle(getString(R.string.select_subtile_track))
.setSingleChoiceItems(
arrayOf(getString(R.string.none)) + tracksGroups.getTrackNames(),
tracksGroups.indexOfFirst { it.isSelected } + 1,
) { dialog, which ->
viewModel.switchToTrack(
TrackType.SUBTITLE,
which - 1,
)
dialog.dismiss()
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
else -> {
throw IllegalStateException("TrackType must be AUDIO or SUBTITLE")
}
val titleResource = when (type) {
C.TRACK_TYPE_AUDIO -> R.string.select_audio_track
C.TRACK_TYPE_TEXT -> R.string.select_subtile_track
else -> throw IllegalStateException("TrackType must be AUDIO or TEXT")
}
val tracksGroups = viewModel.player.currentTracks.groups.filter { it.type == type && it.isSupported }
return activity?.let { activity ->
val builder = MaterialAlertDialogBuilder(activity)
builder
.setTitle(getString(titleResource))
.setSingleChoiceItems(
arrayOf(getString(R.string.none)) + tracksGroups.getTrackNames(), // Add "None" at the top of the list
tracksGroups.indexOfFirst { it.isSelected } + 1, // Add 1 to the index to account for the "None" item
) { dialog, which ->
viewModel.switchToTrack(
type,
which - 1, // Minus 1 to get the correct group without the "None" item. "None" becomes -1
)
dialog.dismiss()
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}

View file

@ -354,7 +354,7 @@ class MPVPlayer(
* @param id Id to select or [C.INDEX_UNSET] to disable [TrackType]
* @return true if the track is or was already selected
*/
fun selectTrack(
private fun selectTrack(
trackType: TrackType,
id: String,
) {

View file

@ -11,6 +11,7 @@ import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.TrackSelectionParameters
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer
@ -20,7 +21,6 @@ import dev.jdtech.jellyfin.AppPreferences
import dev.jdtech.jellyfin.models.Intro
import dev.jdtech.jellyfin.models.PlayerItem
import dev.jdtech.jellyfin.mpv.MPVPlayer
import dev.jdtech.jellyfin.mpv.TrackType
import dev.jdtech.jellyfin.player.video.R
import dev.jdtech.jellyfin.repository.JellyfinRepository
import dev.jdtech.jellyfin.utils.bif.BifData
@ -319,21 +319,22 @@ constructor(
releasePlayer()
}
fun switchToTrack(trackType: TrackType, index: Int) {
if (player is MPVPlayer) {
// Index -1 equals disable track
if (index == -1) {
player.selectTrack(trackType, id = "no")
return
}
// Get track to select based on index
val tracksGroup = player.currentTracks.groups.filter { TrackType.fromMedia3TrackType(it.type) == trackType }[index]
val format = tracksGroup.mediaTrackGroup.getFormat(0)
if (format.id == null) {
return
}
player.selectTrack(trackType, id = format.id!!)
fun switchToTrack(trackType: @C.TrackType Int, index: Int) {
// Index -1 equals disable track
if (index == -1) {
player.trackSelectionParameters = player.trackSelectionParameters
.buildUpon()
.clearOverridesOfType(trackType)
.setTrackTypeDisabled(trackType, true)
.build()
} else {
player.trackSelectionParameters = player.trackSelectionParameters
.buildUpon()
.setOverrideForType(
TrackSelectionOverride(player.currentTracks.groups.filter { it.type == trackType && it.isSupported }[index].mediaTrackGroup, 0),
)
.setTrackTypeDisabled(trackType, false)
.build()
}
}