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:
parent
db5eab1ab2
commit
55427036b2
5 changed files with 49 additions and 128 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
) {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue