Live video on the AT Protocol
1import {
2 Chat,
3 ChatBox,
4 Loader,
5 Resizable,
6 Text,
7 useHandle,
8 useLivestreamInfo,
9 View,
10 zero,
11} from "@streamplace/components";
12import { useKeyboard } from "hooks/useKeyboard";
13import { useEffect } from "react";
14import { Pressable } from "react-native";
15import Animated, {
16 useAnimatedStyle,
17 useSharedValue,
18 withSpring,
19} from "react-native-reanimated";
20import { useResponsiveLayout } from "./useResponsiveLayout";
21
22import { useNavigation } from "@react-navigation/native";
23import { usePDSAgent } from "@streamplace/components/src/streamplace-store/xrpc";
24import { ArrowRight } from "@tamagui/lucide-icons";
25import emojiData from "assets/emoji-data.json";
26const { borderRadius, gap, layout, flex, px, position, bottom } = zero;
27
28export function DesktopChatPanel({
29 chatVisible,
30 chatPanelWidth,
31 safeAreaInsets,
32}) {
33 const sidebarOffset = useSharedValue(chatVisible ? 0 : chatPanelWidth);
34
35 const kb = useKeyboard();
36
37 useEffect(() => {
38 console.log(
39 "Setting sidebar offset x to",
40 chatVisible ? 0 : chatPanelWidth,
41 );
42 sidebarOffset.value = withSpring(chatVisible ? 0 : chatPanelWidth, {
43 damping: 100,
44 stiffness: 1000,
45 });
46 }, [chatVisible, chatPanelWidth, sidebarOffset]);
47
48 const animatedSidebarStyle = useAnimatedStyle(() => ({
49 transform: [
50 { translateX: sidebarOffset.value },
51 { translateY: -kb.keyboardHeight },
52 ],
53 }));
54
55 return (
56 <Animated.View
57 style={[
58 layout.position.absolute,
59 position.right[0],
60 {
61 top: safeAreaInsets.top,
62 bottom: safeAreaInsets.bottom,
63 right: safeAreaInsets.right / 2,
64 width: chatPanelWidth,
65 backgroundColor: "rgba(0, 0, 0, 0.85)",
66 borderLeftWidth: 1,
67 borderLeftColor: "rgba(255, 255, 255, 0.1)",
68 zIndex: 999,
69 },
70 animatedSidebarStyle,
71 ]}
72 >
73 <View style={{ flex: 1, position: "relative" }}>
74 <ChatPanel />
75 </View>
76 </Animated.View>
77 );
78}
79
80// MobileChatPanel.tsx
81export function MobileChatPanel({ isPlayerRatioGreater }) {
82 return (
83 <View
84 style={[
85 isPlayerRatioGreater
86 ? layout.position.relative
87 : layout.position.absolute,
88 bottom[0],
89 { width: "100%", maxWidth: "100%" },
90 ]}
91 >
92 <Resizable
93 isPlayerRatioGreater={isPlayerRatioGreater}
94 startingPercentage={0.4}
95 >
96 <ChatPanel />
97 </Resizable>
98 </View>
99 );
100}
101
102function ChatPanel() {
103 const { shouldShowChatSidePanel, safeAreaInsets } = useResponsiveLayout();
104 const { profile } = useLivestreamInfo();
105 const handle = useHandle();
106
107 let agent = usePDSAgent();
108
109 const navigation = useNavigation();
110 let canModerate = profile?.handle === handle;
111
112 return (
113 <View
114 style={[
115 layout.flex.column,
116 flex.values[1],
117 { width: "100%", maxWidth: "100%" },
118 ]}
119 >
120 <View style={[flex.values[1]]}>
121 <Chat canModerate={canModerate} />
122 </View>
123 <View style={[layout.flex.column, gap.all[2], px[4]]}>
124 {agent?.did ? (
125 <ChatBox
126 emojiData={emojiData}
127 chatBoxStyle={{ borderRadius: borderRadius.xl }}
128 />
129 ) : !agent ? (
130 <View
131 style={[
132 layout.flex.row,
133 layout.flex.center,
134 gap.all[1],
135 zero.p[3],
136 {
137 borderRadius: borderRadius.xl,
138 backgroundColor: "rgba(255, 255, 255, 0.1)",
139 },
140 ]}
141 >
142 <Loader size="large" />
143 </View>
144 ) : (
145 <Pressable
146 onPress={() => navigation.navigate("Login")}
147 style={[
148 layout.flex.row,
149 layout.flex.center,
150 gap.all[2],
151 {
152 padding: 18,
153 borderRadius: borderRadius.xl,
154 backgroundColor: "rgba(255, 255, 255, 0.1)",
155 },
156 ]}
157 >
158 <Text>Log in or sign up to chat</Text>
159 <ArrowRight />
160 </Pressable>
161 )}
162 </View>
163 </View>
164 );
165}