Live video on the AT Protocol

adds a counting timer to the livestream info bar?\ (#165)

* no start?

* timer: UX tweaks

* timer: fix formatting

---------

Co-authored-by: Eli Mallon <eli@stream.place>

authored by

Eli Mallon
Eli Mallon
and committed by
GitHub
f7a5155b b829f6f4

+47
+3
js/app/components/livestream/livestream.tsx
··· 6 6 import PlayerProvider from "components/player/provider"; 7 7 import Popup from "components/popup"; 8 8 import Viewers from "components/viewers"; 9 + import Timer from "components/timer"; 9 10 import { usePlayer } from "features/player/playerSlice"; 10 11 import { 11 12 selectTelemetry, ··· 69 70 const streamerDID = player.livestream?.author?.did; 70 71 const streamerProfile = streamerDID ? profiles[streamerDID] : undefined; 71 72 const streamerHandle = streamerProfile?.handle; 73 + const startTime = player.livestream?.record?.createdAt || Date(); 72 74 73 75 // this would all be really easy if i had library that would give me the 74 76 // safe area view height and width but i don't. so let's measure ··· 262 264 )} 263 265 </View> 264 266 <View flexDirection="row" alignItems="center" gap="$2"> 267 + <Timer start={startTime} /> 265 268 <Viewers viewers={player.viewers ?? 0} /> 266 269 <Button 267 270 backgroundColor="transparent"
+44
js/app/components/timer.tsx
··· 1 + import { View, Text } from "tamagui"; 2 + import { useState, useEffect } from "react"; 3 + 4 + export default function Timer({ start }: { start: string | Date }) { 5 + const [elapsedTime, setElapsedTime] = useState(0); 6 + 7 + useEffect(() => { 8 + const startDate = typeof start === "string" ? new Date(start) : start; 9 + 10 + const interval = setInterval(() => { 11 + const now = new Date(); 12 + const elapsed = Math.floor((now.getTime() - startDate.getTime()) / 1000); 13 + setElapsedTime(elapsed); 14 + }, 250); 15 + 16 + return () => clearInterval(interval); 17 + }, [start]); 18 + 19 + const formatTime = (seconds: number) => { 20 + const hours = Math.floor(seconds / 3600); 21 + const minutes = Math.floor((seconds % 3600) / 60); 22 + const secs = seconds % 60; 23 + 24 + return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`; 25 + }; 26 + 27 + return ( 28 + <View 29 + justifyContent="center" 30 + flexDirection="row" 31 + alignItems="center" 32 + paddingHorizontal="$2" 33 + paddingVertical="$1" 34 + > 35 + <Text 36 + fontFamily="$mono" 37 + textShadowOffset={{ width: -1, height: 1 }} 38 + textShadowRadius={3} 39 + > 40 + {formatTime(elapsedTime)} 41 + </Text> 42 + </View> 43 + ); 44 + }