diff --git a/app/src/main/kotlin/com/muedsa/agetv/ui/features/detail/EpisodeListWidget.kt b/app/src/main/kotlin/com/muedsa/agetv/ui/features/detail/EpisodeListWidget.kt index 790f9b8..1514196 100644 --- a/app/src/main/kotlin/com/muedsa/agetv/ui/features/detail/EpisodeListWidget.kt +++ b/app/src/main/kotlin/com/muedsa/agetv/ui/features/detail/EpisodeListWidget.kt @@ -2,6 +2,8 @@ package com.muedsa.agetv.ui.features.detail import androidx.activity.compose.BackHandler import androidx.compose.foundation.focusable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -18,12 +20,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.graphics.drawscope.scale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.tv.foundation.lazy.list.TvLazyRow @@ -35,6 +38,7 @@ import androidx.tv.material3.WideButton import com.muedsa.agetv.model.dandanplay.DanEpisode import com.muedsa.agetv.room.model.EpisodeProgressModel import com.muedsa.compose.tv.theme.ImageCardRowCardPadding +import kotlin.math.max const val EpisodePageSize = 20 val EpisodeProgressStrokeWidth = 12.dp @@ -109,30 +113,44 @@ fun EpisodeListWidget( items = currentPartEpisodeList, key = { _, item -> item[1] } ) { episodePartIndex, episode -> + val interactionSource = remember { MutableInteractionSource() } + val focusedState = interactionSource.collectIsFocusedAsState() WideButton( modifier = Modifier .padding(end = 12.dp) - .drawBehind { + .drawWithCache { // 进度条 - episodeProgressMap[episode[0]]?.let { model -> - val strokeWidthPx = EpisodeProgressStrokeWidth.toPx() - val wideButtonCornerRadiusPx = WideButtonCornerRadius.toPx() - val width = size.width * model.progress / model.duration - val height = strokeWidthPx / 2 - clipRect( - right = width, - bottom = height - ) { - drawRoundRect( - color = Color.Red, - cornerRadius = CornerRadius( - wideButtonCornerRadiusPx, - wideButtonCornerRadiusPx - ) - ) + val model = episodeProgressMap[episode[0]] + val strokeWidthPx = EpisodeProgressStrokeWidth.toPx() + val wideButtonCornerRadiusPx = WideButtonCornerRadius.toPx() + val width = if (model != null) { + val progressRatio = + model.progress.toFloat() / model.duration + size.width * max(progressRatio, 0.1f) + } else 0f + val height = strokeWidthPx / 2 + val cornerRadius = CornerRadius( + wideButtonCornerRadiusPx, + wideButtonCornerRadiusPx + ) + onDrawWithContent { + drawContent() + if (width > 0) { + scale(if (focusedState.value) 1.1f else 1f) { + clipRect( + right = width, + bottom = height + ) { + drawRoundRect( + color = Color.Red, + cornerRadius = cornerRadius + ) + } + } } } }, + interactionSource = interactionSource, title = { Text(text = episode[0], overflow = TextOverflow.Ellipsis) }, diff --git a/app/src/main/kotlin/com/muedsa/agetv/ui/features/playback/PlaybackScreen.kt b/app/src/main/kotlin/com/muedsa/agetv/ui/features/playback/PlaybackScreen.kt index 81c73b6..2cae076 100644 --- a/app/src/main/kotlin/com/muedsa/agetv/ui/features/playback/PlaybackScreen.kt +++ b/app/src/main/kotlin/com/muedsa/agetv/ui/features/playback/PlaybackScreen.kt @@ -64,6 +64,7 @@ fun PlaybackScreen( if (playerEnd) { if (episodeProgress.aid == aid && exoplayerHolder != null) { val exoPlayer = exoplayerHolder!! + episodeProgress.progress = exoPlayer.duration episodeProgress.duration = exoPlayer.duration episodeProgress.updateAt = System.currentTimeMillis() playbackViewModel.saveEpisodeProgress(episodeProgress) @@ -77,15 +78,17 @@ fun PlaybackScreen( LaunchedEffect(key1 = exoplayerHolder) { if (exoplayerHolder != null) { val exoPlayer = exoplayerHolder!! - delay(10_000) - if (episodeProgress.aid == aid) { - episodeProgress.progress = exoPlayer.currentPosition - episodeProgress.duration = exoPlayer.duration - if (episodeProgress.progress + 5_000 > episodeProgress.duration) { - episodeProgress.progress = max(episodeProgress.duration - 5_000, 0) + while (exoplayerHolder != null) { + delay(10_000) + if (episodeProgress.aid == aid) { + episodeProgress.progress = exoPlayer.currentPosition + episodeProgress.duration = exoPlayer.duration + if (episodeProgress.progress + 5_000 > episodeProgress.duration) { + episodeProgress.progress = max(episodeProgress.duration - 5_000, 0) + } + episodeProgress.updateAt = System.currentTimeMillis() + playbackViewModel.saveEpisodeProgress(episodeProgress) } - episodeProgress.updateAt = System.currentTimeMillis() - playbackViewModel.saveEpisodeProgress(episodeProgress) } } } @@ -119,18 +122,30 @@ fun PlaybackScreen( if (exoplayerHolder == null) { exoplayerHolder = this@DanmakuVideoPlayer if (episodeProgress.progress > 0) { - seekTo(episodeProgress.progress) - val progressStr = episodeProgress.progress - .toDuration(DurationUnit.MILLISECONDS) - .toComponents { hours, minutes, seconds, _ -> - String.format( - "%02d:%02d:%02d", - hours, - minutes, - seconds, - ) + val position = + if (episodeProgress.progress == episodeProgress.duration) { + // 如果上次已经播放完成则不跳转 从头播放 + 0 + } else if (episodeProgress.duration > 5_000 && episodeProgress.progress > episodeProgress.duration - 5_000) { + // 如果太过接近结束的位置 + episodeProgress.duration - 5_000 + } else { + episodeProgress.progress } - errorMsgBoxState.error("跳转到上次播放位置: $progressStr") + if (position > 0) { + seekTo(position) + val positionStr = position + .toDuration(DurationUnit.MILLISECONDS) + .toComponents { hours, minutes, seconds, _ -> + String.format( + "%02d:%02d:%02d", + hours, + minutes, + seconds, + ) + } + errorMsgBoxState.error("跳转到上次播放位置: $positionStr") + } } } }