Live video on the AT Protocol

Merge pull request #724 from streamplace/natb/make-dashboard-scrollable-native

fix: make dashboard properly scrollable on native

authored by Eli Mallon and committed by GitHub 8a5859ca ee616eb7

+51 -49
+26 -29
js/app/components/live-dashboard/bento-grid.tsx
··· 7 7 useProfile, 8 8 useSegment, 9 9 useSegmentTiming, 10 + useTheme, 10 11 zero, 11 12 } from "@streamplace/components"; 12 13 import { 13 14 ProblemsWrapper, 14 15 ProblemsWrapperRef, 15 16 } from "@streamplace/components/src/components/dashboard/problems"; 17 + import { ArrowRight } from "lucide-react-native"; 16 18 import { useCallback, useEffect, useMemo, useRef, useState } from "react"; 17 19 import { Dimensions, Platform, ScrollView, View } from "react-native"; 20 + import { useSafeAreaInsets } from "react-native-safe-area-context"; 18 21 import LivestreamPanel from "./livestream-panel"; 19 22 import StreamMonitor from "./stream-monitor"; 20 23 ··· 61 64 }, [isWeb]); 62 65 63 66 const isDesktop = screenWidth >= 1200; 67 + 68 + const insets = useSafeAreaInsets(); 69 + const { theme } = useTheme(); 64 70 65 71 // Get data from hooks for Dashboard components 66 72 const profile = useProfile(); ··· 208 214 209 215 return ( 210 216 <ProblemsWrapper ref={problemsRef}> 211 - <ScrollView style={[flex.values[1], bg.black]}> 217 + <> 212 218 {/* Header always at top */} 213 219 <View style={[p[4]]}> 214 220 <Dashboard.Header ··· 225 231 onProblemsPress={handleProblemsPress} 226 232 /> 227 233 </View> 228 - 229 - {/* Fixed layout with flex */} 230 - <View 231 - style={[ 232 - flex.values[1], 233 - layout.flex.column, 234 - gap.all[4], 235 - p[4], 236 - { paddingTop: 0 }, 237 - ]} 234 + <ScrollView 235 + contentContainerStyle={{ paddingBottom: insets.bottom }} 236 + style={[flex.values[1], bg.black]} 238 237 > 239 - {/* Stream Monitor Panel */} 240 - <View style={[{ maxHeight: screenHeight * 0.35, height: "100%" }]}> 241 - <StreamMonitor 242 - isLive={isLive} 243 - userProfile={profile} 244 - videoRef={videoRef} 245 - /> 246 - </View> 247 - 248 - {/* Chat Panel - takes remaining space */} 249 - <View style={[flex.values[1], { maxHeight: screenHeight * 0.65 }]}> 238 + <View style={[gap.all[4], p[4], { paddingTop: 0 }]}> 239 + {/* Stream Monitor Panel */} 240 + <View style={[{ height: screenHeight * 0.35 }]}> 241 + <StreamMonitor 242 + isLive={isLive} 243 + userProfile={profile} 244 + videoRef={videoRef} 245 + /> 246 + </View> 250 247 <Button 251 248 disabled={!profile} 252 249 onPress={() => 253 250 navigation.navigate("PopoutChat", { user: profile!.did }) 254 251 } 252 + size="lg" 253 + rightIcon={<ArrowRight size="18" color={theme.colors.text} />} 255 254 > 256 255 Go to chat 257 256 </Button> 258 - </View> 259 - 260 - {/* Livestream Panel */} 261 - <View style={[{ height: "auto" }]}> 262 - <LivestreamPanel /> 257 + <View> 258 + <LivestreamPanel scrollable={false} /> 259 + </View> 263 260 </View> 264 - </View> 265 - </ScrollView> 261 + </ScrollView> 262 + </> 266 263 </ProblemsWrapper> 267 264 ); 268 265 }
+13 -8
js/app/components/live-dashboard/livestream-panel.tsx
··· 160 160 ); 161 161 }; 162 162 163 - function LivestreamPanel() { 163 + function LivestreamPanel({ scrollable = true }: { scrollable?: boolean }) { 164 164 const toast = useToast(); 165 165 const userIsLive = useLiveUser(); 166 166 const captureFrame = useCaptureVideoFrame(); ··· 326 326 return mode === "create" ? "Announce Livestream!" : "Update Livestream!"; 327 327 }, [loading, userIsLive, mode]); 328 328 329 + const Wrapper = scrollable ? ScrollView : View; 330 + const wrapperProps = scrollable 331 + ? { 332 + contentContainerStyle: { 333 + flexGrow: 1, 334 + }, 335 + showsVerticalScrollIndicator: false, 336 + } 337 + : {}; 338 + 329 339 return ( 330 340 <> 331 - <ScrollView 332 - contentContainerStyle={{ 333 - flexGrow: 1, 334 - }} 335 - showsVerticalScrollIndicator={false} 336 - > 341 + <Wrapper {...wrapperProps}> 337 342 <View 338 343 style={[ 339 344 flex.values[1], ··· 573 578 </View> 574 579 )} 575 580 </View> 576 - </ScrollView> 581 + </Wrapper> 577 582 </> 578 583 ); 579 584 }
+7 -6
js/app/components/live-dashboard/stream-key.tsx
··· 3 3 Button, 4 4 Code, 5 5 Row, 6 - View, 6 + Text, 7 7 useTheme, 8 8 useToast, 9 + View, 9 10 } from "@streamplace/components"; 10 11 import { Redirect } from "components/aqlink"; 11 12 import Loading from "components/loading/loading"; ··· 85 86 <FormRow> 86 87 <Label>Output Settings</Label> 87 88 <Content> 88 - <Body> 89 - Output mode: Advanced 90 - <br /> 89 + <Text>Output mode: Advanced</Text> 90 + <Text> 91 91 Keyframe Interval: <Code>1s</Code> 92 - <br /> 92 + </Text> 93 + <Text> 93 94 x264 Options: <Code>bframes=0</Code> 94 - </Body> 95 + </Text> 95 96 </Content> 96 97 </FormRow> 97 98 </View>
+1 -1
js/app/components/settings/settings.tsx
··· 217 217 const isReady = useIsReady(); 218 218 const serverSettings = useServerSettings(); 219 219 const { url } = useStreamplaceNode(); 220 - const { t } = useTranslation(); 220 + const { t } = useTranslation("settings"); 221 221 const debugRecordingOn = serverSettings?.debugRecording === true; 222 222 223 223 useEffect(() => {
+1 -4
js/app/src/screens/live-dashboard.tsx
··· 9 9 import { VideoElementProvider } from "contexts/VideoElementContext"; 10 10 import { useLiveUser } from "hooks/useLiveUser"; 11 11 import { useCallback, useState } from "react"; 12 - import { View } from "react-native"; 13 12 import { useIsReady, useUserProfile } from "store/hooks"; 14 13 15 14 const { flex, bg } = zero; ··· 40 39 <LivestreamProvider src={userProfile.did}> 41 40 <VideoElementProvider videoElement={videoElement}> 42 41 <PlayerProvider> 43 - <View style={[flex.values[1], bg.gray[900]]}> 44 - <BentoGrid isLive={isLive} videoRef={videoRef} /> 45 - </View> 42 + <BentoGrid isLive={isLive} videoRef={videoRef} /> 46 43 </PlayerProvider> 47 44 </VideoElementProvider> 48 45 </LivestreamProvider>
+3 -1
js/components/src/components/content-metadata/content-metadata-form.tsx
··· 684 684 ]} 685 685 > 686 686 <Text 687 + leading="tight" 687 688 style={[ 688 689 text.neutral[300], 689 690 { 690 691 minWidth: 100, 692 + maxWidth: 100, 691 693 textAlign: "left", 692 694 paddingBottom: 8, 693 695 fontSize: 14, 694 696 }, 695 697 ]} 696 698 > 697 - Allowed<br></br>Broadcasters 699 + Allowed Broadcasters 698 700 </Text> 699 701 <View style={[flex.values[1]]}> 700 702 <Text