Implement quality sheet

This commit is contained in:
Secozzi 2024-11-18 11:51:22 +01:00
parent f01083e647
commit ec099e51cf
No known key found for this signature in database
GPG key ID: DD93E0B3A962AA86
7 changed files with 126 additions and 22 deletions

View file

@ -889,7 +889,7 @@ class PlayerActivity : BaseActivity() {
}
}
private fun setVideoList(
fun setVideoList(
qualityIndex: Int,
videos: List<Video>?,
fromStart: Boolean = false,
@ -900,7 +900,7 @@ class PlayerActivity : BaseActivity() {
if (videos == null) return
videos.getOrNull(qualityIndex)?.let {
viewModel.selectVideo(qualityIndex)
viewModel.setVideoIndex(qualityIndex)
setHttpOptions(it)
if (viewModel.isLoadingEpisode.value) {
viewModel.currentEpisode.value?.let { episode ->
@ -940,7 +940,7 @@ class PlayerActivity : BaseActivity() {
private fun setHttpOptions(video: Video) {
if (viewModel.isEpisodeOnline() != true) return
val source = viewModel.currentSource as AnimeHttpSource
val source = viewModel.currentSource.value as? AnimeHttpSource ?: return
val headers = (video.headers ?: source.headers)
.toMultimap()

View file

@ -92,6 +92,7 @@ enum class Sheets {
PlaybackSpeed,
SubtitleTracks,
AudioTracks,
QualityTracks,
Chapters,
Decoders,
More,

View file

@ -227,6 +227,17 @@ class PlayerViewModel @JvmOverloads constructor(
}
}
fun isEpisodeOnline(): Boolean? {
val anime = currentAnime.value ?: return null
val episode = currentEpisode.value ?: return null
val source = currentSource.value ?: return null
return source is AnimeHttpSource &&
!EpisodeLoader.isDownload(
episode.toDomainEpisode()!!,
anime,
)
}
fun updateIsLoadingEpisode(value: Boolean) {
_isLoadingEpisode.update { _ -> value }
}
@ -353,10 +364,21 @@ class PlayerViewModel @JvmOverloads constructor(
_videoList.update { _ -> videoList }
}
fun selectVideo(idx: Int) {
fun setVideoIndex(idx: Int) {
_selectedVideoIndex.update { _ -> idx }
}
fun selectVideo(video: Video) {
val idx = videoList.value.indexOf(video)
activity.setVideoList(
qualityIndex = idx,
videos = videoList.value,
)
sheetShown.update { _ -> Sheets.None }
}
fun addAudio(uri: Uri) {
val url = uri.toString()
val path = if (url.startsWith("content://")) {
@ -885,16 +907,6 @@ class PlayerViewModel @JvmOverloads constructor(
hasTrackers = tracks.isNotEmpty()
}
fun isEpisodeOnline(): Boolean? {
val anime = currentAnime.value ?: return null
val episode = currentEpisode.value ?: return null
return currentSource is AnimeHttpSource &&
!EpisodeLoader.isDownload(
episode.toDomainEpisode()!!,
anime,
)
}
suspend fun loadEpisode(episodeId: Long?): Pair<List<Video>?, String>? {
val anime = currentAnime.value ?: return null
val source = sourceManager.getOrStub(anime.source)

View file

@ -476,7 +476,8 @@ fun PlayerControls(
onSubtitlesLongClick = { onOpenPanel(Panels.SubtitleSettings) },
onAudioClick = { onOpenSheet(Sheets.AudioTracks) },
onAudioLongClick = { onOpenPanel(Panels.AudioDelay) },
onQualityClick = {},
onQualityClick = { onOpenSheet(Sheets.QualityTracks) },
isEpisodeOnline = viewModel.isEpisodeOnline(),
onMoreClick = { onOpenSheet(Sheets.More) },
onMoreLongClick = { onOpenPanel(Panels.VideoFilters) },
)
@ -562,6 +563,8 @@ fun PlayerControls(
val selectedSubtitles by viewModel.selectedSubtitles.collectAsState()
val audioTracks by viewModel.audioTracks.collectAsState()
val selectedAudio by viewModel.selectedAudio.collectAsState()
val videoList by viewModel.videoList.collectAsState()
val selectedVideoIndex by viewModel.selectedVideoIndex.collectAsState()
val decoder by viewModel.currentDecoder.collectAsState()
val speed by viewModel.playbackSpeed.collectAsState()
val sleepTimerTimeRemaining by viewModel.remainingTime.collectAsState()
@ -578,6 +581,11 @@ fun PlayerControls(
selectedAudio = selectedAudio,
onAddAudio = viewModel::addAudio,
onSelectAudio = viewModel::selectAudio,
videoList = videoList.toImmutableList(),
currentVideo = videoList.getOrNull(selectedVideoIndex),
onSelectVideo = { viewModel.selectVideo(it) },
chapter = currentChapter,
chapters = viewModel.chapters.toImmutableList(),
onSeekToChapter = {

View file

@ -5,7 +5,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import dev.vivvvek.seeker.Segment
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.ui.player.Decoder
import eu.kanade.tachiyomi.ui.player.Panels
import eu.kanade.tachiyomi.ui.player.PlayerViewModel.VideoTrack
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.ui.player.controls.components.sheets.ChaptersSheet
import eu.kanade.tachiyomi.ui.player.controls.components.sheets.DecodersSheet
import eu.kanade.tachiyomi.ui.player.controls.components.sheets.MoreSheet
import eu.kanade.tachiyomi.ui.player.controls.components.sheets.PlaybackSpeedSheet
import eu.kanade.tachiyomi.ui.player.controls.components.sheets.QualitySheet
import eu.kanade.tachiyomi.ui.player.controls.components.sheets.SubtitlesSheet
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@ -35,6 +36,11 @@ fun PlayerSheets(
onAddAudio: (Uri) -> Unit,
onSelectAudio: (Int) -> Unit,
// video sheet
videoList: ImmutableList<Video>,
currentVideo: Video?,
onSelectVideo: (Video) -> Unit,
// chapters sheet
chapter: Segment?,
chapters: ImmutableList<Segment>,
@ -94,6 +100,16 @@ fun PlayerSheets(
)
}
Sheets.QualityTracks -> {
if (videoList.isEmpty()) return
QualitySheet(
videoList = videoList,
currentVideo = currentVideo,
onClick = onSelectVideo,
onDismissRequest = onDismissRequest,
)
}
Sheets.Chapters -> {
if (chapter == null) return
ChaptersSheet(

View file

@ -39,6 +39,7 @@ fun TopRightPlayerControls(
// video
onQualityClick: () -> Unit,
isEpisodeOnline: Boolean?,
// more
onMoreClick: () -> Unit,
@ -70,12 +71,14 @@ fun TopRightPlayerControls(
onLongClick = onAudioLongClick,
horizontalSpacing = MaterialTheme.MPVKtSpacing.small,
)
if (isEpisodeOnline == true) {
ControlsButton(
Icons.Default.HighQuality,
onClick = onQualityClick,
onLongClick = onQualityClick,
horizontalSpacing = MaterialTheme.MPVKtSpacing.small,
)
}
ControlsButton(
Icons.Default.MoreVert,
onClick = onMoreClick,

View file

@ -0,0 +1,64 @@
package eu.kanade.tachiyomi.ui.player.controls.components.sheets
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import eu.kanade.tachiyomi.animesource.model.Video
import kotlinx.collections.immutable.ImmutableList
import tachiyomi.presentation.core.components.material.MPVKtSpacing
@Composable
fun QualitySheet(
videoList: ImmutableList<Video>,
currentVideo: Video?,
onClick: (Video) -> Unit,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
) {
GenericTracksSheet(
videoList,
track = {
VideoTrack(
it,
selected = currentVideo == it,
onClick = { onClick(it) },
)
},
onDismissRequest = onDismissRequest,
modifier = modifier
.padding(vertical = MaterialTheme.MPVKtSpacing.medium),
)
}
@Composable
fun VideoTrack(
video: Video,
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Text(
text = video.quality,
fontStyle = if (selected) FontStyle.Italic else FontStyle.Normal,
fontWeight = if (selected) FontWeight.ExtraBold else FontWeight.Normal,
style = MaterialTheme.typography.bodyMedium,
color = if (selected) MaterialTheme.colorScheme.primary else Color.Unspecified,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(
vertical = MaterialTheme.MPVKtSpacing.smaller,
horizontal = MaterialTheme.MPVKtSpacing.medium,
),
)
}