More subtitle selection fixes (#630)

## Description
Fixes more subtitle selection issues, primarily fixes the sort order of
subtitle streams. But also prefer default subtitle in some cases

Adds test cases for the described situations below

Also adds an option in the More dialog to clear track selections made on
an item/series.

### Related issues
Addresses
https://github.com/damontecres/Wholphin/issues/570#issuecomment-3707255647
&
https://github.com/damontecres/Wholphin/issues/570#issuecomment-3707292928
This commit is contained in:
Ray 2026-01-04 17:06:54 -05:00 committed by GitHub
parent 3d4b06db44
commit 02d6a98ba8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 289 additions and 27 deletions

View file

@ -4,6 +4,7 @@ import android.content.Context
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
@ -29,6 +30,12 @@ data class MoreDialogActions(
var onClickAddPlaylist: (UUID) -> Unit,
)
enum class ClearChosenStreams {
NONE,
ITEM_AND_SERIES,
SERIES,
}
/**
* Build the [DialogItem]s when clicking "More"
*
@ -53,10 +60,12 @@ fun buildMoreDialogItems(
sourceId: UUID?,
watched: Boolean,
favorite: Boolean,
canClearChosenStreams: Boolean,
actions: MoreDialogActions,
onChooseVersion: () -> Unit,
onChooseTracks: (MediaStreamType) -> Unit,
onShowOverview: () -> Unit,
onClearChosenStreams: () -> Unit,
): List<DialogItem> =
buildList {
add(
@ -172,6 +181,16 @@ fun buildMoreDialogItems(
},
)
}
if (canClearChosenStreams) {
add(
DialogItem(
context.getString(R.string.clear_track_choices),
Icons.Default.Delete,
) {
onClearChosenStreams()
},
)
}
add(
DialogItem(
context.getString(R.string.play_with_transcoding),

View file

@ -155,6 +155,7 @@ fun EpisodeDetails(
favorite = ep.data.userData?.isFavorite ?: false,
seriesId = ep.data.seriesId,
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
canClearChosenStreams = chosenStreams?.itemPlayback != null || chosenStreams?.plc != null,
actions = moreActions,
onChooseVersion = {
chooseVersion =
@ -204,6 +205,9 @@ fun EpisodeDetails(
)
}
},
onClearChosenStreams = {
viewModel.clearChosenStreams(chosenStreams)
},
),
)
},

View file

@ -182,4 +182,19 @@ class EpisodeViewModel
release()
navigationManager.navigateTo(destination)
}
fun clearChosenStreams(chosenStreams: ChosenStreams?) {
viewModelScope.launchIO {
itemPlaybackRepository.deleteChosenStreams(chosenStreams)
item.value?.let { item ->
val result =
itemPlaybackRepository.getSelectedTracks(
itemId,
item,
userPreferencesService.getCurrent(),
)
this@EpisodeViewModel.chosenStreams.setValueOnMain(result)
}
}
}
}

View file

@ -193,6 +193,7 @@ fun MovieDetails(
favorite = movie.data.userData?.isFavorite ?: false,
seriesId = null,
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
canClearChosenStreams = chosenStreams?.itemPlayback != null || chosenStreams?.plc != null,
actions = moreActions,
onChooseVersion = {
chooseVersion =
@ -241,6 +242,9 @@ fun MovieDetails(
files = movie.data.mediaSources.orEmpty(),
)
},
onClearChosenStreams = {
viewModel.clearChosenStreams(chosenStreams)
},
),
)
},

View file

@ -247,4 +247,19 @@ class MovieViewModel
release()
navigationManager.navigateTo(destination)
}
fun clearChosenStreams(chosenStreams: ChosenStreams?) {
viewModelScope.launchIO {
itemPlaybackRepository.deleteChosenStreams(chosenStreams)
item.value?.let { item ->
val result =
itemPlaybackRepository.getSelectedTracks(
itemId,
item,
userPreferencesService.getCurrent(),
)
this@MovieViewModel.chosenStreams.setValueOnMain(result)
}
}
}
}

View file

@ -19,6 +19,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.map
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
@ -179,6 +180,7 @@ fun SeriesOverview(
fun buildMoreForEpisode(
ep: BaseItem,
chosenStreams: ChosenStreams?,
fromLongClick: Boolean,
): DialogParams =
DialogParams(
@ -192,6 +194,7 @@ fun SeriesOverview(
favorite = ep.data.userData?.isFavorite ?: false,
seriesId = series.id,
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
canClearChosenStreams = chosenStreams?.itemPlayback != null || chosenStreams?.plc != null,
actions =
MoreDialogActions(
navigateTo = viewModel::navigateTo,
@ -259,6 +262,9 @@ fun SeriesOverview(
files = ep.data.mediaSources.orEmpty(),
)
},
onClearChosenStreams = {
viewModel.clearChosenStreams(ep, chosenStreams)
},
),
)
@ -304,7 +310,7 @@ fun SeriesOverview(
)
},
onLongClick = { ep ->
moreDialog = buildMoreForEpisode(ep, true)
moreDialog = buildMoreForEpisode(ep, chosenStreams, true)
},
playOnClick = { resume ->
rowFocused = EPISODE_ROW
@ -333,7 +339,7 @@ fun SeriesOverview(
},
moreOnClick = {
episodeList?.getOrNull(position.episodeRowIndex)?.let { ep ->
moreDialog = buildMoreForEpisode(ep, false)
moreDialog = buildMoreForEpisode(ep, chosenStreams, false)
}
},
overviewOnClick = {

View file

@ -510,6 +510,16 @@ class SeriesViewModel
}
}
}
fun clearChosenStreams(
item: BaseItem,
chosenStreams: ChosenStreams?,
) {
viewModelScope.launchIO {
itemPlaybackRepository.deleteChosenStreams(chosenStreams)
lookUpChosenTracks(item.id, item)
}
}
}
sealed interface EpisodeList {