diff --git a/components/casting/player/CastTrickplayBubble.tsx b/components/casting/player/CastTrickplayBubble.tsx new file mode 100644 index 000000000..17acf3edd --- /dev/null +++ b/components/casting/player/CastTrickplayBubble.tsx @@ -0,0 +1,86 @@ +/** + * Shared scrub-preview bubble for the casting progress bars. + * + * Renders the trickplay tile (when trickplay data is available) with the scrub + * time as plain text above it, or just the scrub time as plain text. It does NO + * positioning of its own — the slider places it via its `bubbleWidth` prop. + */ + +import { Image } from "expo-image"; +import { View } from "react-native"; +import { Text } from "@/components/common/Text"; +import type { useTrickplay } from "@/hooks/useTrickplay"; +import { formatTrickplayTime } from "@/utils/casting/helpers"; + +type TrickplayReturn = ReturnType; + +interface CastTrickplayBubbleProps { + /** Current trickplay image URL/coordinates, or null. */ + trickPlayUrl: TrickplayReturn["trickPlayUrl"]; + /** Parsed trickplay metadata, or null. */ + trickplayInfo: TrickplayReturn["trickplayInfo"]; + /** Scrub time to display. */ + trickplayTime: { hours: number; minutes: number; seconds: number }; + /** Trickplay tile width in px (220 main player, 140 mini-player). */ + tileWidth: number; +} + +export function CastTrickplayBubble({ + trickPlayUrl, + trickplayInfo, + trickplayTime, + tileWidth, +}: CastTrickplayBubbleProps) { + const timeText = ( + + {formatTrickplayTime(trickplayTime)} + + ); + + // No trickplay: just the plain time text. + if (!trickPlayUrl || !trickplayInfo) { + return timeText; + } + + const { x, y, url } = trickPlayUrl; + const tileHeight = tileWidth / (trickplayInfo.aspectRatio ?? 1.78); + + return ( + + {timeText} + + + + + ); +}