fix(media): stable hover controls, fix text cutoff

- Single hover zone on entire video — no more flickering from competing
  zones. Play button always visible when paused, bottom controls appear
  on hover (works in fullscreen too)
- Media height capped to 50% of window (min 200dp) so post text is
  never pushed off-screen by large media

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-03-17 16:51:44 +02:00
parent 248f38cc47
commit 9a19148da8
2 changed files with 22 additions and 54 deletions
@@ -81,35 +81,25 @@ fun VideoControls(
onViewModeChange: ((ViewMode) -> Unit)? = null,
trailingControls: @Composable (() -> Unit)? = null,
) {
var hoveringCenter by remember { mutableStateOf(false) }
var hoveringBottom by remember { mutableStateOf(false) }
var hovering by remember { mutableStateOf(false) }
Box(
modifier =
modifier
.fillMaxSize()
.clickable { onPlayPause() },
) {
// Center hover zone — top 70% of the video
Box(
modifier =
Modifier
.fillMaxWidth()
.fillMaxSize(0.7f)
.align(Alignment.TopCenter)
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent()
when (event.type) {
PointerEventType.Enter -> hoveringCenter = true
PointerEventType.Exit -> hoveringCenter = false
}
.clickable { onPlayPause() }
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent()
when (event.type) {
PointerEventType.Enter -> hovering = true
PointerEventType.Exit -> hovering = false
}
}
},
)
}
},
) {
// Center play/buffering indicator
if (isBuffering) {
CircularProgressIndicator(
@@ -130,40 +120,14 @@ fun VideoControls(
modifier = Modifier.size(48.dp),
)
}
} else if (hoveringCenter) {
// Show pause button on center hover when playing
IconButton(
onClick = onPlayPause,
modifier = Modifier.align(Alignment.Center).size(64.dp),
) {
Icon(
Icons.Default.Pause,
contentDescription = "Pause",
tint = Color.White,
modifier = Modifier.size(48.dp),
)
}
}
// Bottom controls — show on hover over bottom area
// Bottom controls — show on hover
AnimatedVisibility(
visible = hoveringBottom || !isPlaying,
visible = hovering,
enter = fadeIn(),
exit = fadeOut(),
modifier =
Modifier
.align(Alignment.BottomCenter)
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent()
when (event.type) {
PointerEventType.Enter -> hoveringBottom = true
PointerEventType.Exit -> hoveringBottom = false
}
}
}
},
modifier = Modifier.align(Alignment.BottomCenter),
) {
Column(
modifier =
@@ -129,10 +129,14 @@ fun NoteCard(
)
}
// Cap media height so each media item fits in the visible window
// Subtract ~200dp for card chrome (header, text preview, actions, padding)
// Cap media height to half the window so text is never pushed off-screen
val windowState = LocalWindowState.current
val maxMediaHeight = if (windowState != null) (windowState.size.height - 200.dp) else 400.dp
val maxMediaHeight =
if (windowState != null) {
(windowState.size.height * 0.5f).coerceAtLeast(200.dp)
} else {
400.dp
}
Card(
modifier = modifier.fillMaxWidth(),