mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feature: add resume/pause functionality to PlayerGesturesLayer and update seek duration
This commit is contained in:
@@ -19,13 +19,14 @@ fun PurefinIconButton(
|
||||
icon: ImageVector,
|
||||
contentDescription: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
size: Int = 52
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(52.dp)
|
||||
.size(size.dp)
|
||||
.clip(CircleShape)
|
||||
.background(scheme.secondary)
|
||||
.clickable { onClick() },
|
||||
|
||||
@@ -11,24 +11,19 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.Cast
|
||||
import androidx.compose.material.icons.outlined.Forward10
|
||||
import androidx.compose.material.icons.outlined.Forward30
|
||||
import androidx.compose.material.icons.outlined.LiveTv
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material.icons.outlined.Pause
|
||||
import androidx.compose.material.icons.outlined.PlayArrow
|
||||
import androidx.compose.material.icons.outlined.PlaylistPlay
|
||||
import androidx.compose.material.icons.outlined.Replay10
|
||||
import androidx.compose.material.icons.outlined.Replay30
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.SkipNext
|
||||
import androidx.compose.material.icons.outlined.SkipPrevious
|
||||
import androidx.compose.material.icons.outlined.Subtitles
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -38,7 +33,6 @@ 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.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@@ -94,15 +88,6 @@ fun PlayerControlsOverlay(
|
||||
onOpenQueue = onOpenQueue,
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
CenterControls(
|
||||
isPlaying = uiState.isPlaying,
|
||||
isLive = uiState.isLive,
|
||||
onPlayPause = onPlayPause,
|
||||
onSeekForward = { onSeekRelative(30_000) },
|
||||
onSeekBackward = { onSeekRelative(-10_000) },
|
||||
onSeekLiveEdge = onSeekLiveEdge,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
BottomSection(
|
||||
uiState = uiState,
|
||||
scrubbing = scrubbing,
|
||||
@@ -111,6 +96,10 @@ fun PlayerControlsOverlay(
|
||||
onScrubFinished = { scrubbing = false },
|
||||
onNext = onNext,
|
||||
onPrevious = onPrevious,
|
||||
onPlayPause = onPlayPause,
|
||||
onSeekForward = { onSeekRelative(30_000) },
|
||||
onSeekBackward = { onSeekRelative(-10_000) },
|
||||
onSeekLiveEdge = onSeekLiveEdge,
|
||||
onToggleCaptions = onToggleCaptions,
|
||||
onShowSettings = onShowSettings,
|
||||
onQueueSelected = onQueueSelected,
|
||||
@@ -161,80 +150,6 @@ private fun TopBar(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CenterControls(
|
||||
isPlaying: Boolean,
|
||||
isLive: Boolean,
|
||||
onPlayPause: () -> Unit,
|
||||
onSeekForward: () -> Unit,
|
||||
onSeekBackward: () -> Unit,
|
||||
onSeekLiveEdge: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
OverlayActionButton(
|
||||
icon = Icons.Outlined.Replay10,
|
||||
label = "-10",
|
||||
onClick = onSeekBackward
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.background(scheme.primary.copy(alpha = 0.9f))
|
||||
) {
|
||||
val icon = if (isPlaying) Icons.Outlined.Pause else Icons.Outlined.PlayArrow
|
||||
GhostIconButton(
|
||||
icon = icon,
|
||||
contentDescription = "Play/Pause",
|
||||
onClick = onPlayPause,
|
||||
modifier = Modifier.padding(6.dp)
|
||||
)
|
||||
}
|
||||
OverlayActionButton(
|
||||
icon = Icons.Outlined.Forward30,
|
||||
label = "+30",
|
||||
onClick = onSeekForward
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
if (isLive) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Icon(Icons.Outlined.LiveTv, contentDescription = null, tint = scheme.primary)
|
||||
Text(
|
||||
text = "Live",
|
||||
color = scheme.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.background(scheme.primary.copy(alpha = 0.15f))
|
||||
.padding(horizontal = 10.dp, vertical = 6.dp)
|
||||
)
|
||||
Text(
|
||||
text = "Catch up",
|
||||
color = scheme.onSurface,
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.background(scheme.surfaceVariant.copy(alpha = 0.7f))
|
||||
.clickable { onSeekLiveEdge() }
|
||||
.padding(horizontal = 12.dp, vertical = 6.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomSection(
|
||||
uiState: PlayerUiState,
|
||||
@@ -244,6 +159,10 @@ private fun BottomSection(
|
||||
onScrubFinished: () -> Unit,
|
||||
onNext: () -> Unit,
|
||||
onPrevious: () -> Unit,
|
||||
onPlayPause: () -> Unit,
|
||||
onSeekForward: () -> Unit,
|
||||
onSeekBackward: () -> Unit,
|
||||
onSeekLiveEdge: () -> Unit,
|
||||
onToggleCaptions: () -> Unit,
|
||||
onShowSettings: () -> Unit,
|
||||
onQueueSelected: (String) -> Unit,
|
||||
@@ -255,7 +174,8 @@ private fun BottomSection(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = formatTime(uiState.positionMs),
|
||||
@@ -263,7 +183,17 @@ private fun BottomSection(
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
if (uiState.isLive) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = "LIVE", color = scheme.primary, fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
text = "Catch up",
|
||||
color = scheme.onSurface,
|
||||
modifier = Modifier.clickable { onSeekLiveEdge() }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = formatTime(uiState.durationMs),
|
||||
@@ -283,26 +213,52 @@ private fun BottomSection(
|
||||
onScrubFinished = onScrubFinished
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
PurefinIconButton(
|
||||
icon = Icons.Outlined.SkipPrevious,
|
||||
contentDescription = "Previous",
|
||||
onClick = onPrevious
|
||||
onClick = onPrevious,
|
||||
size = 64
|
||||
)
|
||||
PurefinIconButton(
|
||||
icon = Icons.Outlined.Replay10,
|
||||
contentDescription = "Seek backward",
|
||||
onClick = onSeekBackward,
|
||||
size = 64
|
||||
)
|
||||
PurefinIconButton(
|
||||
icon = if (uiState.isPlaying) Icons.Outlined.Pause else Icons.Outlined.PlayArrow,
|
||||
contentDescription = "Play/Pause",
|
||||
onClick = onPlayPause,
|
||||
size = 64
|
||||
)
|
||||
PurefinIconButton(
|
||||
icon = Icons.Outlined.Forward30,
|
||||
contentDescription = "Seek forward",
|
||||
onClick = onSeekForward,
|
||||
size = 64
|
||||
)
|
||||
PurefinIconButton(
|
||||
icon = Icons.Outlined.SkipNext,
|
||||
contentDescription = "Next",
|
||||
onClick = onNext
|
||||
onClick = onNext,
|
||||
size = 64
|
||||
)
|
||||
}
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
PurefinIconButton(
|
||||
icon = Icons.Outlined.Subtitles,
|
||||
contentDescription = "Captions",
|
||||
@@ -319,23 +275,6 @@ private fun BottomSection(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OverlayActionButton(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
label: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
GhostIconButton(
|
||||
icon = icon,
|
||||
contentDescription = label,
|
||||
onClick = onClick
|
||||
)
|
||||
Text(text = label, color = scheme.onSurface, style = MaterialTheme.typography.labelSmall)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatTime(positionMs: Long): String {
|
||||
val totalSeconds = positionMs / 1000
|
||||
val seconds = (totalSeconds % 60).toInt()
|
||||
|
||||
Reference in New Issue
Block a user