kasunk99-livestream-core 0.3.13 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5,9 +5,6 @@ type LiveStreamViewerItemProps = {
|
|
|
5
5
|
isActive: boolean;
|
|
6
6
|
index: number;
|
|
7
7
|
};
|
|
8
|
-
/**
|
|
9
|
-
* Single full-screen viewer cell. When isActive, joins the stream room and consumes video/audio.
|
|
10
|
-
*/
|
|
11
8
|
export declare const LiveStreamViewerItem: React.NamedExoticComponent<LiveStreamViewerItemProps>;
|
|
12
9
|
export {};
|
|
13
10
|
//# sourceMappingURL=LiveStreamViewerItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStreamViewerItem.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamViewerItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveStreamViewerItem.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamViewerItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAiB1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ/C,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAiCF,eAAO,MAAM,oBAAoB,uDA8Z/B,CAAC"}
|
|
@@ -1,40 +1,28 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { ActivityIndicator, Dimensions,
|
|
4
|
-
// react-native-keyboard-controller handles Android/iOS keyboard edge cases better
|
|
5
|
-
// than the built-in KeyboardAvoidingView. Fall back to the built-in if unavailable.
|
|
6
|
-
let KAV = KeyboardAvoidingView;
|
|
7
|
-
try {
|
|
8
|
-
KAV = require('react-native-keyboard-controller').KeyboardAvoidingView;
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
// use built-in
|
|
12
|
-
}
|
|
3
|
+
import { ActivityIndicator, Animated, Dimensions, Keyboard, NativeModules, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native';
|
|
13
4
|
import { useViewerSocket } from '../hooks/useViewerSocket';
|
|
14
5
|
const SCREEN_HEIGHT = Dimensions.get('window').height;
|
|
15
6
|
const CHAT_NAME_COLORS = ['#f97316', '#22c55e', '#3b82f6', '#eab308', '#ec4899', '#a855f7'];
|
|
16
|
-
// iOS needs bottom safe-area padding; Android auto-adjusts via adjustResize
|
|
17
7
|
const BOTTOM_SAFE = Platform.OS === 'ios' ? 28 : 10;
|
|
8
|
+
const BOTTOM_BAR_H = 58;
|
|
9
|
+
const CHAT_BOTTOM_DEFAULT = BOTTOM_SAFE + BOTTOM_BAR_H + 8;
|
|
18
10
|
let RTCViewComponent = null;
|
|
19
11
|
try {
|
|
20
12
|
const webrtc = require('react-native-webrtc');
|
|
21
13
|
RTCViewComponent = webrtc.RTCView;
|
|
22
14
|
}
|
|
23
|
-
catch {
|
|
24
|
-
// react-native-webrtc not available in Expo Go
|
|
25
|
-
}
|
|
26
|
-
// expo-linear-gradient — lazy require so the package stays safe in non-Expo environments.
|
|
27
|
-
// The consuming app (social-casino-mobile) has expo-linear-gradient as a dependency.
|
|
15
|
+
catch { }
|
|
28
16
|
let LinearGradient = null;
|
|
29
17
|
try {
|
|
30
18
|
LinearGradient = require('expo-linear-gradient').LinearGradient;
|
|
31
19
|
}
|
|
32
|
-
catch {
|
|
33
|
-
|
|
20
|
+
catch { }
|
|
21
|
+
let RNKCEvents = null;
|
|
22
|
+
try {
|
|
23
|
+
RNKCEvents = require('react-native-keyboard-controller').KeyboardEvents;
|
|
34
24
|
}
|
|
35
|
-
|
|
36
|
-
* Single full-screen viewer cell. When isActive, joins the stream room and consumes video/audio.
|
|
37
|
-
*/
|
|
25
|
+
catch { }
|
|
38
26
|
export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream, isActive, index: _index, }) {
|
|
39
27
|
const roomId = isActive ? stream.roomId : null;
|
|
40
28
|
const { joined, joining, error, producerList, roomState, remoteStream, remoteVideoStream, webrtcUnavailable, consumeError, socket, viewerCount: liveViewerCount, streamEnded, } = useViewerSocket(roomId);
|
|
@@ -53,8 +41,31 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
53
41
|
const showVideo = RTCViewComponent && remoteStream && !!streamURL && hasVideoTrack;
|
|
54
42
|
const [chatInput, setChatInput] = useState('');
|
|
55
43
|
const [chatMessages, setChatMessages] = useState([]);
|
|
44
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
56
45
|
const seededRoomRef = useRef(null);
|
|
57
46
|
const chatListRef = useRef(null);
|
|
47
|
+
const textInputRef = useRef(null);
|
|
48
|
+
// Keyboard-driven animated positions
|
|
49
|
+
const inputBottom = useRef(new Animated.Value(0)).current;
|
|
50
|
+
const chatAnim = useRef(new Animated.Value(CHAT_BOTTOM_DEFAULT)).current;
|
|
51
|
+
// Animate floating input and chat column with keyboard
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const animate = (toInput, toChat, dur, onDone) => {
|
|
54
|
+
Animated.parallel([
|
|
55
|
+
Animated.timing(inputBottom, { toValue: toInput, duration: dur, useNativeDriver: false }),
|
|
56
|
+
Animated.timing(chatAnim, { toValue: toChat, duration: dur, useNativeDriver: false }),
|
|
57
|
+
]).start(() => onDone?.());
|
|
58
|
+
};
|
|
59
|
+
if (RNKCEvents) {
|
|
60
|
+
const s1 = RNKCEvents.addListener('keyboardWillShow', (e) => animate(e.height, e.height + 60, e.duration || 250));
|
|
61
|
+
const s2 = RNKCEvents.addListener('keyboardWillHide', (e) => animate(0, CHAT_BOTTOM_DEFAULT, e.duration || 250, () => setIsTyping(false)));
|
|
62
|
+
return () => { s1.remove(); s2.remove(); };
|
|
63
|
+
}
|
|
64
|
+
// Standard Keyboard API fallback
|
|
65
|
+
const sub1 = Keyboard.addListener((Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'), (e) => animate(e.endCoordinates.height, e.endCoordinates.height + 60, e.duration || 250));
|
|
66
|
+
const sub2 = Keyboard.addListener((Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'), (e) => animate(0, CHAT_BOTTOM_DEFAULT, e.duration || 200, () => setIsTyping(false)));
|
|
67
|
+
return () => { sub1.remove(); sub2.remove(); };
|
|
68
|
+
}, [inputBottom, chatAnim]);
|
|
58
69
|
const seededFromRoomState = useMemo(() => {
|
|
59
70
|
const chat = roomState && typeof roomState === 'object'
|
|
60
71
|
? roomState.chat
|
|
@@ -66,6 +77,10 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
66
77
|
seededRoomRef.current = null;
|
|
67
78
|
setChatMessages([]);
|
|
68
79
|
setChatInput('');
|
|
80
|
+
setIsTyping(false);
|
|
81
|
+
Keyboard.dismiss();
|
|
82
|
+
inputBottom.setValue(0);
|
|
83
|
+
chatAnim.setValue(CHAT_BOTTOM_DEFAULT);
|
|
69
84
|
return;
|
|
70
85
|
}
|
|
71
86
|
if (seededRoomRef.current !== roomId) {
|
|
@@ -73,7 +88,7 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
73
88
|
setChatMessages([]);
|
|
74
89
|
setChatInput('');
|
|
75
90
|
}
|
|
76
|
-
}, [roomId]);
|
|
91
|
+
}, [roomId, inputBottom, chatAnim]);
|
|
77
92
|
useEffect(() => {
|
|
78
93
|
if (!roomId)
|
|
79
94
|
return;
|
|
@@ -145,7 +160,6 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
145
160
|
}
|
|
146
161
|
catch { /* ignore */ }
|
|
147
162
|
}, [chatData.length]);
|
|
148
|
-
// System audio playback (Android only)
|
|
149
163
|
useEffect(() => {
|
|
150
164
|
if (!socket || !joined || !isActive || Platform.OS !== 'android')
|
|
151
165
|
return;
|
|
@@ -197,12 +211,8 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
197
211
|
};
|
|
198
212
|
const hostLabel = stream.hostDisplayName || stream.title || 'Live';
|
|
199
213
|
const avatarLetter = hostLabel[0]?.toUpperCase() ?? 'L';
|
|
200
|
-
return (_jsxs(
|
|
201
|
-
|
|
202
|
-
'rgba(0,0,0,0.0)', // clears out ~30% down
|
|
203
|
-
'rgba(0,0,0,0.0)', // stays clear through mid-screen
|
|
204
|
-
'rgba(0,0,0,0.78)', // darkens toward bottom for chat / input
|
|
205
|
-
], locations: [0, 0.28, 0.48, 1], style: styles.gradientOverlay, pointerEvents: "none" })) : null, _jsxs(View, { style: styles.topBar, pointerEvents: "box-none", children: [_jsxs(View, { style: styles.hostRow, pointerEvents: "none", children: [_jsx(View, { style: styles.avatar, children: _jsx(Text, { style: styles.avatarLetter, children: avatarLetter }) }), _jsx(Text, { style: styles.hostName, numberOfLines: 1, children: hostLabel }), _jsx(View, { style: styles.livePill, children: _jsx(Text, { style: styles.livePillText, children: "LIVE" }) })] }), _jsxs(View, { style: styles.viewerChip, pointerEvents: "none", children: [_jsx(Text, { style: styles.viewerEye, children: "\uD83D\uDC41" }), _jsx(Text, { style: styles.viewerCount, children: viewerCount > 0 ? viewerCount.toLocaleString() : '—' })] })] }), _jsxs(View, { style: styles.rightColumn, pointerEvents: "box-none", children: [_jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\u2665" }) }), _jsx(Text, { style: styles.actionLabel, children: "Like" })] }), _jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\uD83C\uDF81" }) }), _jsx(Text, { style: styles.actionLabel, children: "Gift" })] }), _jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\u2197" }) }), _jsx(Text, { style: styles.actionLabel, children: "Share" })] })] }), _jsxs(View, { style: styles.bottomSection, pointerEvents: "box-none", children: [_jsx(View, { style: styles.chatColumn, pointerEvents: "box-none", children: _jsx(ScrollView, { ref: chatListRef, contentContainerStyle: styles.chatContent, showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "always", keyboardDismissMode: "none", children: chatData.map((item) => item.displayName ? (_jsx(View, { style: styles.chatBubble, children: _jsxs(Text, { style: styles.chatLine, numberOfLines: 3, children: [_jsxs(Text, { style: [styles.chatUsername, { color: getNameColor(item.displayName) }], children: [item.displayName, ' '] }), _jsx(Text, { style: styles.chatMsg, children: item.text })] }) }, item.id)) : (_jsx(View, { style: styles.joinBubble, children: _jsx(Text, { style: styles.joinText, children: item.text }) }, item.id))) }) }), _jsxs(View, { style: styles.inputBar, children: [_jsx(TouchableOpacity, { style: styles.inputIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.inputIconGlyph, children: "\u263A" }) }), _jsx(TextInput, { style: styles.textInput, value: chatInput, onChangeText: setChatInput, placeholder: joined ? 'Say something...' : 'Connecting...', placeholderTextColor: "rgba(255,255,255,0.35)", editable: joined && !joining && !error, onSubmitEditing: sendChat, returnKeyType: "send", submitBehavior: "submit" }), _jsx(TouchableOpacity, { style: styles.inputIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.inputIconGlyph, children: "\uD83C\uDF39" }) }), _jsx(TouchableOpacity, { style: [styles.sendBtn, (!chatInput.trim() || !joined) && styles.sendBtnOff], onPress: sendChat, activeOpacity: 0.75, disabled: !joined || !chatInput.trim(), children: _jsx(Text, { style: styles.sendIcon, children: "\u25B6" }) })] })] }), streamEnded && (_jsx(View, { style: styles.endedOverlay, children: _jsxs(View, { style: styles.endedCard, children: [_jsx(Text, { style: styles.endedTitle, children: "Stream ended" }), _jsx(Text, { style: styles.endedSub, children: "The host has ended this live stream" })] }) }))] }));
|
|
214
|
+
return (_jsxs(View, { style: styles.container, children: [showVideo && RTCViewComponent && streamURL ? (_jsx(RTCViewComponent, { streamURL: streamURL, stream: displayStream, style: styles.rtcView, objectFit: "cover", mirror: false }, `rtc-${trackCount}-${streamURL}`)) : (_jsxs(View, { style: styles.videoPlaceholder, children: [joining && _jsx(ActivityIndicator, { size: "large", color: "rgba(255,255,255,0.6)" }), !joining && error && _jsx(Text, { style: styles.placeholderError, children: error }), joined && !joining && !error && hasVideo && !remoteStream && (_jsx(ActivityIndicator, { size: "large", color: "rgba(255,255,255,0.45)" })), joined && !joining && !error && hasVideo && webrtcUnavailable && (_jsx(Text, { style: styles.placeholderHint, children: "Video needs a development build" })), joined && !joining && !error && hasVideo && consumeError && (_jsx(Text, { style: styles.placeholderError, children: consumeError }))] })), LinearGradient ? (_jsx(LinearGradient, { colors: ['rgba(0,0,0,0.70)', 'rgba(0,0,0,0.0)', 'rgba(0,0,0,0.0)', 'rgba(0,0,0,0.78)'], locations: [0, 0.28, 0.48, 1], style: styles.gradientOverlay, pointerEvents: "none" })) : null, _jsxs(View, { style: styles.topBar, pointerEvents: "box-none", children: [_jsxs(View, { style: styles.hostRow, pointerEvents: "none", children: [_jsx(View, { style: styles.avatar, children: _jsx(Text, { style: styles.avatarLetter, children: avatarLetter }) }), _jsx(Text, { style: styles.hostName, numberOfLines: 1, children: hostLabel }), _jsx(View, { style: styles.livePill, children: _jsx(Text, { style: styles.livePillText, children: "LIVE" }) })] }), _jsxs(View, { style: styles.viewerChip, pointerEvents: "none", children: [_jsx(Text, { style: styles.viewerEye, children: "\uD83D\uDC41" }), _jsx(Text, { style: styles.viewerCount, children: viewerCount > 0 ? viewerCount.toLocaleString() : '—' })] })] }), !isTyping && (_jsxs(View, { style: styles.rightColumn, pointerEvents: "box-none", children: [_jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\u2665" }) }), _jsx(Text, { style: styles.actionLabel, children: "Like" })] }), _jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\uD83C\uDF81" }) }), _jsx(Text, { style: styles.actionLabel, children: "Gift" })] }), _jsxs(TouchableOpacity, { style: styles.actionBtn, activeOpacity: 0.75, children: [_jsx(View, { style: styles.actionCircle, children: _jsx(Text, { style: styles.actionIcon, children: "\u2197" }) }), _jsx(Text, { style: styles.actionLabel, children: "Share" })] })] })), _jsx(Animated.View, { style: [styles.chatColumn, { bottom: chatAnim }], pointerEvents: "box-none", children: _jsx(ScrollView, { ref: chatListRef, contentContainerStyle: styles.chatContent, showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "always", keyboardDismissMode: "on-drag", children: chatData.map((item) => item.displayName ? (_jsx(View, { style: styles.chatBubble, children: _jsxs(Text, { style: styles.chatLine, numberOfLines: 3, children: [_jsxs(Text, { style: [styles.chatUsername, { color: getNameColor(item.displayName) }], children: [item.displayName, ' '] }), _jsx(Text, { style: styles.chatMsg, children: item.text })] }) }, item.id)) : (_jsx(View, { style: styles.joinBubble, children: _jsx(Text, { style: styles.joinText, children: item.text }) }, item.id))) }) }), !isTyping && (_jsxs(View, { style: styles.bottomBar, children: [_jsx(TouchableOpacity, { style: styles.typeTouchable, onPress: () => { if (joined && !joining && !error)
|
|
215
|
+
setIsTyping(true); }, activeOpacity: 0.7, children: _jsx(Text, { style: styles.typePlaceholder, children: joined && !joining ? 'Say something...' : 'Connecting...' }) }), _jsx(TouchableOpacity, { style: styles.bottomIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.bottomIconGlyph, children: "\u263A" }) }), _jsx(TouchableOpacity, { style: styles.bottomIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.bottomIconGlyph, children: "\uD83C\uDF39" }) }), _jsx(TouchableOpacity, { style: styles.bottomIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.bottomIconGlyph, children: "\uD83C\uDF81" }) }), _jsx(TouchableOpacity, { style: styles.bottomIconBtn, activeOpacity: 0.7, children: _jsx(Text, { style: styles.bottomIconGlyph, children: "\u2197" }) })] })), isTyping && (_jsxs(Animated.View, { style: [styles.floatingInputWrap, { bottom: inputBottom }], children: [_jsx(TextInput, { ref: textInputRef, style: styles.floatingTextInput, value: chatInput, onChangeText: setChatInput, placeholder: "Say something...", placeholderTextColor: "rgba(255,255,255,0.40)", editable: joined && !joining && !error, onSubmitEditing: sendChat, returnKeyType: "send", submitBehavior: "submit", autoFocus: true }), _jsx(TouchableOpacity, { style: [styles.floatingSendBtn, (!chatInput.trim() || !joined) && styles.sendBtnOff], onPress: sendChat, disabled: !joined || !chatInput.trim(), activeOpacity: 0.75, children: _jsx(Text, { style: styles.sendIcon, children: "\u25B6" }) })] })), streamEnded && (_jsx(View, { style: styles.endedOverlay, children: _jsxs(View, { style: styles.endedCard, children: [_jsx(Text, { style: styles.endedTitle, children: "Stream ended" }), _jsx(Text, { style: styles.endedSub, children: "The host has ended this live stream" })] }) }))] }));
|
|
206
216
|
});
|
|
207
217
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
208
218
|
const styles = StyleSheet.create({
|
|
@@ -210,7 +220,6 @@ const styles = StyleSheet.create({
|
|
|
210
220
|
flex: 1,
|
|
211
221
|
backgroundColor: '#000',
|
|
212
222
|
},
|
|
213
|
-
// ── Video ─────────────────────────────────────────────────────────────────
|
|
214
223
|
rtcView: {
|
|
215
224
|
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
216
225
|
backgroundColor: '#000',
|
|
@@ -234,7 +243,9 @@ const styles = StyleSheet.create({
|
|
|
234
243
|
textAlign: 'center',
|
|
235
244
|
paddingHorizontal: 28,
|
|
236
245
|
},
|
|
237
|
-
|
|
246
|
+
gradientOverlay: {
|
|
247
|
+
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
248
|
+
},
|
|
238
249
|
topBar: {
|
|
239
250
|
position: 'absolute',
|
|
240
251
|
top: 10,
|
|
@@ -263,17 +274,8 @@ const styles = StyleSheet.create({
|
|
|
263
274
|
justifyContent: 'center',
|
|
264
275
|
flexShrink: 0,
|
|
265
276
|
},
|
|
266
|
-
avatarLetter: {
|
|
267
|
-
|
|
268
|
-
fontSize: 15,
|
|
269
|
-
fontWeight: '700',
|
|
270
|
-
},
|
|
271
|
-
hostName: {
|
|
272
|
-
color: '#fff',
|
|
273
|
-
fontSize: 14,
|
|
274
|
-
fontWeight: '600',
|
|
275
|
-
flex: 1,
|
|
276
|
-
},
|
|
277
|
+
avatarLetter: { color: '#fff', fontSize: 15, fontWeight: '700' },
|
|
278
|
+
hostName: { color: '#fff', fontSize: 14, fontWeight: '600', flex: 1 },
|
|
277
279
|
livePill: {
|
|
278
280
|
backgroundColor: '#ef4444',
|
|
279
281
|
borderRadius: 6,
|
|
@@ -281,12 +283,7 @@ const styles = StyleSheet.create({
|
|
|
281
283
|
paddingVertical: 3,
|
|
282
284
|
flexShrink: 0,
|
|
283
285
|
},
|
|
284
|
-
livePillText: {
|
|
285
|
-
color: '#fff',
|
|
286
|
-
fontSize: 11,
|
|
287
|
-
fontWeight: '700',
|
|
288
|
-
letterSpacing: 0.8,
|
|
289
|
-
},
|
|
286
|
+
livePillText: { color: '#fff', fontSize: 11, fontWeight: '700', letterSpacing: 0.8 },
|
|
290
287
|
viewerChip: {
|
|
291
288
|
flexDirection: 'row',
|
|
292
289
|
alignItems: 'center',
|
|
@@ -298,23 +295,15 @@ const styles = StyleSheet.create({
|
|
|
298
295
|
flexShrink: 0,
|
|
299
296
|
},
|
|
300
297
|
viewerEye: { fontSize: 11 },
|
|
301
|
-
viewerCount: {
|
|
302
|
-
color: 'rgba(255,255,255,0.88)',
|
|
303
|
-
fontSize: 12,
|
|
304
|
-
fontWeight: '500',
|
|
305
|
-
},
|
|
306
|
-
// ── Right action column ───────────────────────────────────────────────────
|
|
298
|
+
viewerCount: { color: 'rgba(255,255,255,0.88)', fontSize: 12, fontWeight: '500' },
|
|
307
299
|
rightColumn: {
|
|
308
300
|
position: 'absolute',
|
|
309
301
|
right: 12,
|
|
310
|
-
bottom:
|
|
302
|
+
bottom: BOTTOM_SAFE + BOTTOM_BAR_H + 8,
|
|
311
303
|
alignItems: 'center',
|
|
312
304
|
gap: 14,
|
|
313
305
|
},
|
|
314
|
-
actionBtn: {
|
|
315
|
-
alignItems: 'center',
|
|
316
|
-
gap: 5,
|
|
317
|
-
},
|
|
306
|
+
actionBtn: { alignItems: 'center', gap: 5 },
|
|
318
307
|
actionCircle: {
|
|
319
308
|
width: 48,
|
|
320
309
|
height: 48,
|
|
@@ -325,31 +314,16 @@ const styles = StyleSheet.create({
|
|
|
325
314
|
alignItems: 'center',
|
|
326
315
|
justifyContent: 'center',
|
|
327
316
|
},
|
|
328
|
-
actionIcon: {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
},
|
|
332
|
-
actionLabel: {
|
|
333
|
-
color: 'rgba(255,255,255,0.7)',
|
|
334
|
-
fontSize: 11,
|
|
335
|
-
fontWeight: '500',
|
|
336
|
-
},
|
|
337
|
-
// ── Bottom section (in-flow — KAV lifts this above the keyboard) ─────────
|
|
338
|
-
bottomSection: {
|
|
339
|
-
flex: 1,
|
|
340
|
-
justifyContent: 'flex-end',
|
|
341
|
-
paddingHorizontal: 12,
|
|
342
|
-
paddingBottom: BOTTOM_SAFE,
|
|
343
|
-
gap: 8,
|
|
344
|
-
},
|
|
345
|
-
// Chat messages
|
|
317
|
+
actionIcon: { fontSize: 22, color: '#fff' },
|
|
318
|
+
actionLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 11, fontWeight: '500' },
|
|
319
|
+
// Chat column — absolute, bottom driven by animation
|
|
346
320
|
chatColumn: {
|
|
321
|
+
position: 'absolute',
|
|
322
|
+
left: 12,
|
|
347
323
|
width: '66%',
|
|
348
324
|
maxHeight: Math.round(SCREEN_HEIGHT * 0.30),
|
|
349
325
|
},
|
|
350
|
-
chatContent: {
|
|
351
|
-
paddingBottom: 2,
|
|
352
|
-
},
|
|
326
|
+
chatContent: { paddingBottom: 2 },
|
|
353
327
|
chatBubble: {
|
|
354
328
|
alignSelf: 'flex-start',
|
|
355
329
|
marginBottom: 5,
|
|
@@ -368,53 +342,57 @@ const styles = StyleSheet.create({
|
|
|
368
342
|
paddingVertical: 4,
|
|
369
343
|
maxWidth: '100%',
|
|
370
344
|
},
|
|
371
|
-
chatLine: {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
},
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
},
|
|
382
|
-
joinText: {
|
|
383
|
-
color: 'rgba(255,255,255,0.48)',
|
|
384
|
-
fontSize: 12,
|
|
385
|
-
fontStyle: 'italic',
|
|
386
|
-
},
|
|
387
|
-
// Input bar
|
|
388
|
-
inputBar: {
|
|
345
|
+
chatLine: { fontSize: 13, lineHeight: 18 },
|
|
346
|
+
chatUsername: { fontWeight: '700' },
|
|
347
|
+
chatMsg: { color: '#e5e5e5', fontWeight: '400' },
|
|
348
|
+
joinText: { color: 'rgba(255,255,255,0.48)', fontSize: 12, fontStyle: 'italic' },
|
|
349
|
+
// Bottom action bar
|
|
350
|
+
bottomBar: {
|
|
351
|
+
position: 'absolute',
|
|
352
|
+
bottom: BOTTOM_SAFE,
|
|
353
|
+
left: 12,
|
|
354
|
+
right: 12,
|
|
389
355
|
flexDirection: 'row',
|
|
390
356
|
alignItems: 'center',
|
|
391
|
-
|
|
392
|
-
borderRadius: 999,
|
|
393
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
394
|
-
borderColor: 'rgba(255,255,255,0.12)',
|
|
395
|
-
paddingHorizontal: 4,
|
|
396
|
-
paddingVertical: 4,
|
|
397
|
-
gap: 2,
|
|
357
|
+
gap: 6,
|
|
398
358
|
},
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
alignItems: 'center',
|
|
403
|
-
justifyContent: 'center',
|
|
359
|
+
typeTouchable: {
|
|
360
|
+
flex: 1,
|
|
361
|
+
backgroundColor: 'rgba(255,255,255,0.12)',
|
|
404
362
|
borderRadius: 20,
|
|
363
|
+
paddingHorizontal: 14,
|
|
364
|
+
paddingVertical: 10,
|
|
365
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
366
|
+
borderColor: 'rgba(255,255,255,0.18)',
|
|
405
367
|
},
|
|
406
|
-
|
|
407
|
-
|
|
368
|
+
typePlaceholder: { color: 'rgba(255,255,255,0.50)', fontSize: 14 },
|
|
369
|
+
bottomIconBtn: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center' },
|
|
370
|
+
bottomIconGlyph: { fontSize: 22 },
|
|
371
|
+
// Floating input bar — sits directly above keyboard, animated
|
|
372
|
+
floatingInputWrap: {
|
|
373
|
+
position: 'absolute',
|
|
374
|
+
left: 0,
|
|
375
|
+
right: 0,
|
|
376
|
+
flexDirection: 'row',
|
|
377
|
+
alignItems: 'center',
|
|
378
|
+
backgroundColor: 'rgba(20,20,20,0.96)',
|
|
379
|
+
paddingHorizontal: 12,
|
|
380
|
+
paddingVertical: 8,
|
|
381
|
+
gap: 8,
|
|
382
|
+
borderTopWidth: StyleSheet.hairlineWidth,
|
|
383
|
+
borderTopColor: 'rgba(255,255,255,0.10)',
|
|
408
384
|
},
|
|
409
|
-
|
|
385
|
+
floatingTextInput: {
|
|
410
386
|
flex: 1,
|
|
387
|
+
backgroundColor: 'rgba(255,255,255,0.10)',
|
|
388
|
+
borderRadius: 20,
|
|
389
|
+
paddingHorizontal: 14,
|
|
390
|
+
paddingVertical: Platform.OS === 'ios' ? 10 : 8,
|
|
411
391
|
color: '#fff',
|
|
412
392
|
fontSize: 14,
|
|
413
|
-
paddingHorizontal: 6,
|
|
414
|
-
paddingVertical: Platform.OS === 'ios' ? 10 : 6,
|
|
415
393
|
minHeight: 40,
|
|
416
394
|
},
|
|
417
|
-
|
|
395
|
+
floatingSendBtn: {
|
|
418
396
|
width: 40,
|
|
419
397
|
height: 40,
|
|
420
398
|
borderRadius: 20,
|
|
@@ -422,42 +400,15 @@ const styles = StyleSheet.create({
|
|
|
422
400
|
alignItems: 'center',
|
|
423
401
|
justifyContent: 'center',
|
|
424
402
|
},
|
|
425
|
-
sendBtnOff: {
|
|
426
|
-
|
|
427
|
-
},
|
|
428
|
-
sendIcon: {
|
|
429
|
-
color: '#fff',
|
|
430
|
-
fontSize: 15,
|
|
431
|
-
fontWeight: '700',
|
|
432
|
-
},
|
|
433
|
-
// ── Stream ended ──────────────────────────────────────────────────────────
|
|
403
|
+
sendBtnOff: { backgroundColor: 'rgba(255,255,255,0.12)' },
|
|
404
|
+
sendIcon: { color: '#fff', fontSize: 15, fontWeight: '700' },
|
|
434
405
|
endedOverlay: {
|
|
435
406
|
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
436
407
|
backgroundColor: 'rgba(0,0,0,0.80)',
|
|
437
408
|
alignItems: 'center',
|
|
438
409
|
justifyContent: 'center',
|
|
439
410
|
},
|
|
440
|
-
endedCard: {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
paddingHorizontal: 36,
|
|
444
|
-
},
|
|
445
|
-
endedTitle: {
|
|
446
|
-
color: '#fff',
|
|
447
|
-
fontSize: 22,
|
|
448
|
-
fontWeight: '700',
|
|
449
|
-
},
|
|
450
|
-
endedSub: {
|
|
451
|
-
color: 'rgba(255,255,255,0.5)',
|
|
452
|
-
fontSize: 14,
|
|
453
|
-
textAlign: 'center',
|
|
454
|
-
lineHeight: 20,
|
|
455
|
-
},
|
|
456
|
-
gradientOverlay: {
|
|
457
|
-
position: 'absolute',
|
|
458
|
-
top: 0,
|
|
459
|
-
left: 0,
|
|
460
|
-
right: 0,
|
|
461
|
-
bottom: 0,
|
|
462
|
-
},
|
|
411
|
+
endedCard: { alignItems: 'center', gap: 10, paddingHorizontal: 36 },
|
|
412
|
+
endedTitle: { color: '#fff', fontSize: 22, fontWeight: '700' },
|
|
413
|
+
endedSub: { color: 'rgba(255,255,255,0.5)', fontSize: 14, textAlign: 'center', lineHeight: 20 },
|
|
463
414
|
});
|
package/package.json
CHANGED