kasunk99-livestream-core 0.3.13 → 0.3.15
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;AAmB1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAU/C,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAwBF,eAAO,MAAM,oBAAoB,uDAka/B,CAAC"}
|
|
@@ -1,40 +1,25 @@
|
|
|
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, KeyboardAvoidingView, NativeModules, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native';
|
|
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, KeyboardAvoidingView, Modal, 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;
|
|
10
|
+
// Chat shifts up when keyboard is open — fixed offset works with both adjustResize + adjustNothing
|
|
11
|
+
const CHAT_BOTTOM_TYPING = BOTTOM_SAFE + 8;
|
|
18
12
|
let RTCViewComponent = null;
|
|
19
13
|
try {
|
|
20
14
|
const webrtc = require('react-native-webrtc');
|
|
21
15
|
RTCViewComponent = webrtc.RTCView;
|
|
22
16
|
}
|
|
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.
|
|
17
|
+
catch { }
|
|
28
18
|
let LinearGradient = null;
|
|
29
19
|
try {
|
|
30
20
|
LinearGradient = require('expo-linear-gradient').LinearGradient;
|
|
31
21
|
}
|
|
32
|
-
catch {
|
|
33
|
-
// expo-linear-gradient not available
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Single full-screen viewer cell. When isActive, joins the stream room and consumes video/audio.
|
|
37
|
-
*/
|
|
22
|
+
catch { }
|
|
38
23
|
export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream, isActive, index: _index, }) {
|
|
39
24
|
const roomId = isActive ? stream.roomId : null;
|
|
40
25
|
const { joined, joining, error, producerList, roomState, remoteStream, remoteVideoStream, webrtcUnavailable, consumeError, socket, viewerCount: liveViewerCount, streamEnded, } = useViewerSocket(roomId);
|
|
@@ -53,8 +38,25 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
53
38
|
const showVideo = RTCViewComponent && remoteStream && !!streamURL && hasVideoTrack;
|
|
54
39
|
const [chatInput, setChatInput] = useState('');
|
|
55
40
|
const [chatMessages, setChatMessages] = useState([]);
|
|
41
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
56
42
|
const seededRoomRef = useRef(null);
|
|
57
43
|
const chatListRef = useRef(null);
|
|
44
|
+
const textInputRef = useRef(null);
|
|
45
|
+
// Animates chat column up/down when keyboard opens/closes
|
|
46
|
+
const chatAnim = useRef(new Animated.Value(CHAT_BOTTOM_DEFAULT)).current;
|
|
47
|
+
// Slide chat column based on typing state
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
Animated.timing(chatAnim, {
|
|
50
|
+
toValue: isTyping ? CHAT_BOTTOM_TYPING : CHAT_BOTTOM_DEFAULT,
|
|
51
|
+
duration: 220,
|
|
52
|
+
useNativeDriver: false,
|
|
53
|
+
}).start();
|
|
54
|
+
}, [isTyping, chatAnim]);
|
|
55
|
+
// When keyboard fully hides, close the floating input modal
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const sub = Keyboard.addListener('keyboardDidHide', () => setIsTyping(false));
|
|
58
|
+
return () => sub.remove();
|
|
59
|
+
}, []);
|
|
58
60
|
const seededFromRoomState = useMemo(() => {
|
|
59
61
|
const chat = roomState && typeof roomState === 'object'
|
|
60
62
|
? roomState.chat
|
|
@@ -66,6 +68,9 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
66
68
|
seededRoomRef.current = null;
|
|
67
69
|
setChatMessages([]);
|
|
68
70
|
setChatInput('');
|
|
71
|
+
setIsTyping(false);
|
|
72
|
+
Keyboard.dismiss();
|
|
73
|
+
chatAnim.setValue(CHAT_BOTTOM_DEFAULT);
|
|
69
74
|
return;
|
|
70
75
|
}
|
|
71
76
|
if (seededRoomRef.current !== roomId) {
|
|
@@ -73,7 +78,7 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
73
78
|
setChatMessages([]);
|
|
74
79
|
setChatInput('');
|
|
75
80
|
}
|
|
76
|
-
}, [roomId]);
|
|
81
|
+
}, [roomId, chatAnim]);
|
|
77
82
|
useEffect(() => {
|
|
78
83
|
if (!roomId)
|
|
79
84
|
return;
|
|
@@ -145,7 +150,6 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
145
150
|
}
|
|
146
151
|
catch { /* ignore */ }
|
|
147
152
|
}, [chatData.length]);
|
|
148
|
-
// System audio playback (Android only)
|
|
149
153
|
useEffect(() => {
|
|
150
154
|
if (!socket || !joined || !isActive || Platform.OS !== 'android')
|
|
151
155
|
return;
|
|
@@ -197,12 +201,8 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
197
201
|
};
|
|
198
202
|
const hostLabel = stream.hostDisplayName || stream.title || 'Live';
|
|
199
203
|
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" })] }) }))] }));
|
|
204
|
+
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", 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)
|
|
205
|
+
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" }) })] })), 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" })] }) })), _jsx(Modal, { visible: isTyping, transparent: true, animationType: "none", statusBarTranslucent: true, onRequestClose: () => Keyboard.dismiss(), children: _jsxs(KeyboardAvoidingView, { style: styles.inputModalKAV, behavior: Platform.OS === 'ios' ? 'padding' : 'height', children: [_jsx(TouchableOpacity, { style: styles.inputModalBackdrop, activeOpacity: 1, onPress: () => Keyboard.dismiss() }), _jsxs(View, { style: styles.floatingInputWrap, 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" }) })] })] }) })] }));
|
|
206
206
|
});
|
|
207
207
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
208
208
|
const styles = StyleSheet.create({
|
|
@@ -210,7 +210,6 @@ const styles = StyleSheet.create({
|
|
|
210
210
|
flex: 1,
|
|
211
211
|
backgroundColor: '#000',
|
|
212
212
|
},
|
|
213
|
-
// ── Video ─────────────────────────────────────────────────────────────────
|
|
214
213
|
rtcView: {
|
|
215
214
|
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
216
215
|
backgroundColor: '#000',
|
|
@@ -234,7 +233,9 @@ const styles = StyleSheet.create({
|
|
|
234
233
|
textAlign: 'center',
|
|
235
234
|
paddingHorizontal: 28,
|
|
236
235
|
},
|
|
237
|
-
|
|
236
|
+
gradientOverlay: {
|
|
237
|
+
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
238
|
+
},
|
|
238
239
|
topBar: {
|
|
239
240
|
position: 'absolute',
|
|
240
241
|
top: 10,
|
|
@@ -263,17 +264,8 @@ const styles = StyleSheet.create({
|
|
|
263
264
|
justifyContent: 'center',
|
|
264
265
|
flexShrink: 0,
|
|
265
266
|
},
|
|
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
|
-
},
|
|
267
|
+
avatarLetter: { color: '#fff', fontSize: 15, fontWeight: '700' },
|
|
268
|
+
hostName: { color: '#fff', fontSize: 14, fontWeight: '600', flex: 1 },
|
|
277
269
|
livePill: {
|
|
278
270
|
backgroundColor: '#ef4444',
|
|
279
271
|
borderRadius: 6,
|
|
@@ -281,12 +273,7 @@ const styles = StyleSheet.create({
|
|
|
281
273
|
paddingVertical: 3,
|
|
282
274
|
flexShrink: 0,
|
|
283
275
|
},
|
|
284
|
-
livePillText: {
|
|
285
|
-
color: '#fff',
|
|
286
|
-
fontSize: 11,
|
|
287
|
-
fontWeight: '700',
|
|
288
|
-
letterSpacing: 0.8,
|
|
289
|
-
},
|
|
276
|
+
livePillText: { color: '#fff', fontSize: 11, fontWeight: '700', letterSpacing: 0.8 },
|
|
290
277
|
viewerChip: {
|
|
291
278
|
flexDirection: 'row',
|
|
292
279
|
alignItems: 'center',
|
|
@@ -298,23 +285,15 @@ const styles = StyleSheet.create({
|
|
|
298
285
|
flexShrink: 0,
|
|
299
286
|
},
|
|
300
287
|
viewerEye: { fontSize: 11 },
|
|
301
|
-
viewerCount: {
|
|
302
|
-
color: 'rgba(255,255,255,0.88)',
|
|
303
|
-
fontSize: 12,
|
|
304
|
-
fontWeight: '500',
|
|
305
|
-
},
|
|
306
|
-
// ── Right action column ───────────────────────────────────────────────────
|
|
288
|
+
viewerCount: { color: 'rgba(255,255,255,0.88)', fontSize: 12, fontWeight: '500' },
|
|
307
289
|
rightColumn: {
|
|
308
290
|
position: 'absolute',
|
|
309
291
|
right: 12,
|
|
310
|
-
bottom:
|
|
292
|
+
bottom: BOTTOM_SAFE + BOTTOM_BAR_H + 8,
|
|
311
293
|
alignItems: 'center',
|
|
312
294
|
gap: 14,
|
|
313
295
|
},
|
|
314
|
-
actionBtn: {
|
|
315
|
-
alignItems: 'center',
|
|
316
|
-
gap: 5,
|
|
317
|
-
},
|
|
296
|
+
actionBtn: { alignItems: 'center', gap: 5 },
|
|
318
297
|
actionCircle: {
|
|
319
298
|
width: 48,
|
|
320
299
|
height: 48,
|
|
@@ -325,31 +304,16 @@ const styles = StyleSheet.create({
|
|
|
325
304
|
alignItems: 'center',
|
|
326
305
|
justifyContent: 'center',
|
|
327
306
|
},
|
|
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
|
|
307
|
+
actionIcon: { fontSize: 22, color: '#fff' },
|
|
308
|
+
actionLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 11, fontWeight: '500' },
|
|
309
|
+
// Chat column — absolute, bottom animated between default and typing positions
|
|
346
310
|
chatColumn: {
|
|
311
|
+
position: 'absolute',
|
|
312
|
+
left: 12,
|
|
347
313
|
width: '66%',
|
|
348
314
|
maxHeight: Math.round(SCREEN_HEIGHT * 0.30),
|
|
349
315
|
},
|
|
350
|
-
chatContent: {
|
|
351
|
-
paddingBottom: 2,
|
|
352
|
-
},
|
|
316
|
+
chatContent: { paddingBottom: 2 },
|
|
353
317
|
chatBubble: {
|
|
354
318
|
alignSelf: 'flex-start',
|
|
355
319
|
marginBottom: 5,
|
|
@@ -368,53 +332,61 @@ const styles = StyleSheet.create({
|
|
|
368
332
|
paddingVertical: 4,
|
|
369
333
|
maxWidth: '100%',
|
|
370
334
|
},
|
|
371
|
-
chatLine: {
|
|
372
|
-
|
|
373
|
-
|
|
335
|
+
chatLine: { fontSize: 13, lineHeight: 18 },
|
|
336
|
+
chatUsername: { fontWeight: '700' },
|
|
337
|
+
chatMsg: { color: '#e5e5e5', fontWeight: '400' },
|
|
338
|
+
joinText: { color: 'rgba(255,255,255,0.48)', fontSize: 12, fontStyle: 'italic' },
|
|
339
|
+
// Bottom action bar
|
|
340
|
+
bottomBar: {
|
|
341
|
+
position: 'absolute',
|
|
342
|
+
bottom: BOTTOM_SAFE,
|
|
343
|
+
left: 12,
|
|
344
|
+
right: 12,
|
|
345
|
+
flexDirection: 'row',
|
|
346
|
+
alignItems: 'center',
|
|
347
|
+
gap: 6,
|
|
374
348
|
},
|
|
375
|
-
|
|
376
|
-
|
|
349
|
+
typeTouchable: {
|
|
350
|
+
flex: 1,
|
|
351
|
+
backgroundColor: 'rgba(255,255,255,0.12)',
|
|
352
|
+
borderRadius: 20,
|
|
353
|
+
paddingHorizontal: 14,
|
|
354
|
+
paddingVertical: 10,
|
|
355
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
356
|
+
borderColor: 'rgba(255,255,255,0.18)',
|
|
377
357
|
},
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
358
|
+
typePlaceholder: { color: 'rgba(255,255,255,0.50)', fontSize: 14 },
|
|
359
|
+
bottomIconBtn: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center' },
|
|
360
|
+
bottomIconGlyph: { fontSize: 22 },
|
|
361
|
+
// Modal input overlay
|
|
362
|
+
inputModalKAV: {
|
|
363
|
+
flex: 1,
|
|
381
364
|
},
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
fontSize: 12,
|
|
385
|
-
fontStyle: 'italic',
|
|
365
|
+
inputModalBackdrop: {
|
|
366
|
+
flex: 1,
|
|
386
367
|
},
|
|
387
|
-
|
|
388
|
-
inputBar: {
|
|
368
|
+
floatingInputWrap: {
|
|
389
369
|
flexDirection: 'row',
|
|
390
370
|
alignItems: 'center',
|
|
391
|
-
backgroundColor: 'rgba(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
},
|
|
399
|
-
inputIconBtn: {
|
|
400
|
-
width: 40,
|
|
401
|
-
height: 40,
|
|
402
|
-
alignItems: 'center',
|
|
403
|
-
justifyContent: 'center',
|
|
404
|
-
borderRadius: 20,
|
|
405
|
-
},
|
|
406
|
-
inputIconGlyph: {
|
|
407
|
-
fontSize: 21,
|
|
371
|
+
backgroundColor: 'rgba(20,20,20,0.97)',
|
|
372
|
+
paddingHorizontal: 12,
|
|
373
|
+
paddingVertical: 8,
|
|
374
|
+
paddingBottom: BOTTOM_SAFE,
|
|
375
|
+
gap: 8,
|
|
376
|
+
borderTopWidth: StyleSheet.hairlineWidth,
|
|
377
|
+
borderTopColor: 'rgba(255,255,255,0.10)',
|
|
408
378
|
},
|
|
409
|
-
|
|
379
|
+
floatingTextInput: {
|
|
410
380
|
flex: 1,
|
|
381
|
+
backgroundColor: 'rgba(255,255,255,0.10)',
|
|
382
|
+
borderRadius: 20,
|
|
383
|
+
paddingHorizontal: 14,
|
|
384
|
+
paddingVertical: Platform.OS === 'ios' ? 10 : 8,
|
|
411
385
|
color: '#fff',
|
|
412
386
|
fontSize: 14,
|
|
413
|
-
paddingHorizontal: 6,
|
|
414
|
-
paddingVertical: Platform.OS === 'ios' ? 10 : 6,
|
|
415
387
|
minHeight: 40,
|
|
416
388
|
},
|
|
417
|
-
|
|
389
|
+
floatingSendBtn: {
|
|
418
390
|
width: 40,
|
|
419
391
|
height: 40,
|
|
420
392
|
borderRadius: 20,
|
|
@@ -422,42 +394,15 @@ const styles = StyleSheet.create({
|
|
|
422
394
|
alignItems: 'center',
|
|
423
395
|
justifyContent: 'center',
|
|
424
396
|
},
|
|
425
|
-
sendBtnOff: {
|
|
426
|
-
|
|
427
|
-
},
|
|
428
|
-
sendIcon: {
|
|
429
|
-
color: '#fff',
|
|
430
|
-
fontSize: 15,
|
|
431
|
-
fontWeight: '700',
|
|
432
|
-
},
|
|
433
|
-
// ── Stream ended ──────────────────────────────────────────────────────────
|
|
397
|
+
sendBtnOff: { backgroundColor: 'rgba(255,255,255,0.12)' },
|
|
398
|
+
sendIcon: { color: '#fff', fontSize: 15, fontWeight: '700' },
|
|
434
399
|
endedOverlay: {
|
|
435
400
|
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
|
|
436
401
|
backgroundColor: 'rgba(0,0,0,0.80)',
|
|
437
402
|
alignItems: 'center',
|
|
438
403
|
justifyContent: 'center',
|
|
439
404
|
},
|
|
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
|
-
},
|
|
405
|
+
endedCard: { alignItems: 'center', gap: 10, paddingHorizontal: 36 },
|
|
406
|
+
endedTitle: { color: '#fff', fontSize: 22, fontWeight: '700' },
|
|
407
|
+
endedSub: { color: 'rgba(255,255,255,0.5)', fontSize: 14, textAlign: 'center', lineHeight: 20 },
|
|
463
408
|
});
|
package/package.json
CHANGED