kasunk99-livestream-core 0.3.38 โ 0.3.40
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStreamViewerItem.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamViewerItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkE,MAAM,OAAO,CAAC;AAmBvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveStreamViewerItem.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamViewerItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkE,MAAM,OAAO,CAAC;AAmBvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAmB/C,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD,CAAC;AAmEF,eAAO,MAAM,oBAAoB,uDAsiB/B,CAAC"}
|
|
@@ -5,6 +5,17 @@ import { useViewerSocket } from '../hooks/useViewerSocket';
|
|
|
5
5
|
const CHAT_NAME_COLORS = ['#f97316', '#22c55e', '#3b82f6', '#eab308', '#ec4899', '#a855f7'];
|
|
6
6
|
const BOTTOM_SAFE = Platform.OS === 'ios' ? 28 : 10;
|
|
7
7
|
const BRAND_GREEN = '#009F68';
|
|
8
|
+
const EMOJIS = [
|
|
9
|
+
'๐', '๐', '๐', '๐คฃ', '๐', '๐', '๐
', '๐', '๐', '๐',
|
|
10
|
+
'๐', '๐', '๐', '๐ฅฐ', '๐', '๐คฉ', '๐ฅณ', '๐', '๐', '๐',
|
|
11
|
+
'๐ค', '๐ก', '๐คฌ', '๐ญ', '๐ข', '๐ฑ', '๐จ', '๐ค', '๐คญ', '๐ด',
|
|
12
|
+
'โค๏ธ', '๐งก', '๐', '๐', '๐', '๐', '๐ค', '๐ค', '๐', '๐',
|
|
13
|
+
'๐ฏ', '๐ฅ', 'โจ', 'โญ', '๐', '๐ฅ', '๐', '๐', '๐', '๐',
|
|
14
|
+
'๐', '๐', '๐', '๐', '๐', 'โ๏ธ', '๐ค', '๐ค', '๐ช', '๐',
|
|
15
|
+
'๐', '๐ป', '๐', '๐ถ', '๐ฑ', '๐ผ', '๐ฆ', '๐ธ', '๐ฆ', '๐ธ',
|
|
16
|
+
'๐', '๐', '๐', '๐ฎ', '๐', '๐ฃ', '๐ฐ', '๐', '๐ซ', '๐ญ',
|
|
17
|
+
'โฝ', '๐', '๐ฎ', '๐ต', '๐ถ', '๐ฑ', '๐ป', '๐ธ', '๐', '๐',
|
|
18
|
+
];
|
|
8
19
|
let RTCViewComponent = null;
|
|
9
20
|
try {
|
|
10
21
|
const webrtc = require('react-native-webrtc');
|
|
@@ -62,6 +73,7 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
62
73
|
const [chatMessages, setChatMessages] = useState([]);
|
|
63
74
|
// isTyping controls whether we show the TextInput bar or the pill bar
|
|
64
75
|
const [isTyping, setIsTyping] = useState(false);
|
|
76
|
+
const [showEmoji, setShowEmoji] = useState(false);
|
|
65
77
|
const [floatingHearts, setFloatingHearts] = useState([]);
|
|
66
78
|
const heartIdRef = useRef(0);
|
|
67
79
|
const handleLike = useCallback(() => {
|
|
@@ -76,6 +88,29 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
76
88
|
setFloatingHearts((prev) => prev.filter((h) => h.id !== id));
|
|
77
89
|
});
|
|
78
90
|
}, [joined, emitLike]);
|
|
91
|
+
const openEmoji = useCallback(() => {
|
|
92
|
+
Keyboard.dismiss();
|
|
93
|
+
setIsTyping(false);
|
|
94
|
+
setShowEmoji(true);
|
|
95
|
+
}, []);
|
|
96
|
+
// Switches from emoji panel back to system keyboard
|
|
97
|
+
const switchToKeyboard = useCallback(() => {
|
|
98
|
+
setShowEmoji(false);
|
|
99
|
+
setIsTyping(true);
|
|
100
|
+
}, []);
|
|
101
|
+
// Focus TextInput programmatically when switching to keyboard mode (not emoji mode)
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (isTyping && !showEmoji) {
|
|
104
|
+
const t = setTimeout(() => textInputRef.current?.focus(), 50);
|
|
105
|
+
return () => clearTimeout(t);
|
|
106
|
+
}
|
|
107
|
+
}, [isTyping, showEmoji]);
|
|
108
|
+
const handleEmojiSelect = useCallback((emoji) => {
|
|
109
|
+
const next = chatInputRef.current + emoji;
|
|
110
|
+
chatInputRef.current = next;
|
|
111
|
+
setChatInput(next);
|
|
112
|
+
// Input bar is already visible (showEmoji=true), no state change needed
|
|
113
|
+
}, []);
|
|
79
114
|
// Incremented every time the app returns to foreground โ forces RTCView to remount,
|
|
80
115
|
// which restarts the Android SurfaceView renderer that freezes during background.
|
|
81
116
|
const [videoKey, setVideoKey] = useState(0);
|
|
@@ -106,6 +141,7 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
106
141
|
if (!isActive) {
|
|
107
142
|
Keyboard.dismiss();
|
|
108
143
|
setIsTyping(false);
|
|
144
|
+
setShowEmoji(false);
|
|
109
145
|
}
|
|
110
146
|
}, [isActive]);
|
|
111
147
|
const seededFromRoomState = useMemo(() => {
|
|
@@ -263,6 +299,8 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
263
299
|
chatInputRef.current = '';
|
|
264
300
|
setChatInput('');
|
|
265
301
|
Keyboard.dismiss();
|
|
302
|
+
setShowEmoji(false);
|
|
303
|
+
setIsTyping(false);
|
|
266
304
|
};
|
|
267
305
|
const hostLabel = stream.hostDisplayName || stream.title || 'Live';
|
|
268
306
|
const avatarLetter = hostLabel[0]?.toUpperCase() ?? 'L';
|
|
@@ -279,14 +317,16 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
279
317
|
],
|
|
280
318
|
opacity: anim.interpolate({ inputRange: [0, 0.65, 1], outputRange: [1, 0.85, 0] }),
|
|
281
319
|
},
|
|
282
|
-
], children: "\u2665" }, id))) }), isTyping ? (_jsxs(View, { style: styles.inputBar, children: [_jsx(TextInput, { ref: textInputRef, style: styles.textInput, value: chatInput, onChangeText: (text) => { chatInputRef.current = text; setChatInput(text); }, placeholder: "Say something...", placeholderTextColor: "rgba(255,255,255,0.40)", editable: canType, onSubmitEditing: sendChat, returnKeyType: "send", submitBehavior: "submit"
|
|
320
|
+
], children: "\u2665" }, id))) }), isTyping || showEmoji ? (_jsxs(View, { style: styles.inputBar, children: [_jsx(TouchableOpacity, { style: styles.emojiToggleBtn, onPress: showEmoji ? switchToKeyboard : openEmoji, activeOpacity: 0.7, hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }, children: _jsx(Text, { style: [styles.bottomIconGlyph, showEmoji && styles.emojiIconActive], children: showEmoji ? 'โจ' : 'โบ' }) }), _jsx(TextInput, { ref: textInputRef, style: styles.textInput, value: chatInput, onChangeText: (text) => { chatInputRef.current = text; setChatInput(text); }, placeholder: "Say something...", placeholderTextColor: "rgba(255,255,255,0.40)", editable: canType, onFocus: () => setShowEmoji(false), onSubmitEditing: sendChat, returnKeyType: "send", submitBehavior: "submit" }), RNGHTouchable ? (_jsx(RNGHTouchable, { onPress: sendChat, activeOpacity: 0.75, style: [styles.sendBtn, (!hasUnsent || !joined) && styles.sendBtnOff], hitSlop: { top: 8, right: 8, bottom: 8, left: 8 }, children: IoniconsComponent
|
|
283
321
|
? _jsx(IoniconsComponent, { name: "send", size: 18, color: "#fff" })
|
|
284
322
|
: _jsx(Text, { style: styles.sendIcon, children: "\u27A4" }) })) : (_jsx(Pressable, { style: [styles.sendBtn, (!hasUnsent || !joined) && styles.sendBtnOff], onPressIn: sendChat, hitSlop: { top: 8, right: 8, bottom: 8, left: 8 }, children: IoniconsComponent
|
|
285
323
|
? _jsx(IoniconsComponent, { name: "send", size: 18, color: "#fff" })
|
|
286
324
|
: _jsx(Text, { style: styles.sendIcon, children: "\u27A4" }) }))] })) : (
|
|
287
|
-
// Pill bar โ
|
|
288
|
-
_jsxs(View, { style: styles.bottomBar, children: [_jsx(TouchableOpacity, { style: [styles.typeTouchable, hasUnsent && styles.typeTouchableFilled], onPress: () => { if (canType)
|
|
289
|
-
|
|
325
|
+
// Pill bar โ shown when neither keyboard nor emoji panel is active
|
|
326
|
+
_jsxs(View, { style: styles.bottomBar, children: [_jsx(TouchableOpacity, { style: [styles.typeTouchable, hasUnsent && styles.typeTouchableFilled], onPress: () => { if (canType) {
|
|
327
|
+
setShowEmoji(false);
|
|
328
|
+
setIsTyping(true);
|
|
329
|
+
} }, activeOpacity: 0.7, children: _jsx(Text, { style: [styles.typePlaceholder, hasUnsent && styles.typePlaceholderFilled], numberOfLines: 1, children: hasUnsent ? chatInput : (joined && !joining ? 'Say something...' : 'Connecting...') }) }), _jsx(TouchableOpacity, { style: styles.bottomIconBtn, activeOpacity: 0.7, onPress: openEmoji, children: _jsx(Text, { style: styles.bottomIconGlyph, children: "\u263A" }) }), _jsx(TouchableOpacity, { style: styles.likeBtn, onPress: handleLike, activeOpacity: 0.75, children: _jsx(Text, { style: [styles.bottomIconGlyph, styles.heartIcon], children: "\u2665" }) })] })), showEmoji ? (_jsx(View, { style: styles.emojiContainer, children: _jsx(ScrollView, { style: styles.emojiScroll, showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "always", children: _jsx(View, { style: styles.emojiGrid, children: EMOJIS.map((emoji, idx) => (_jsx(TouchableOpacity, { style: styles.emojiCell, onPress: () => handleEmojiSelect(emoji), activeOpacity: 0.6, children: _jsx(Text, { style: styles.emojiText, children: emoji }) }, idx))) }) }) })) : null, 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" })] }) }))] }));
|
|
290
330
|
});
|
|
291
331
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
292
332
|
const styles = StyleSheet.create({
|
|
@@ -488,4 +528,27 @@ const styles = StyleSheet.create({
|
|
|
488
528
|
endedCard: { alignItems: 'center', gap: 10, paddingHorizontal: 36 },
|
|
489
529
|
endedTitle: { color: '#fff', fontSize: 22, fontWeight: '700' },
|
|
490
530
|
endedSub: { color: 'rgba(255,255,255,0.5)', fontSize: 14, textAlign: 'center', lineHeight: 20 },
|
|
531
|
+
// โโ Emoji picker โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
532
|
+
emojiToggleBtn: { width: 36, height: 40, alignItems: 'center', justifyContent: 'center' },
|
|
533
|
+
emojiIconActive: { color: BRAND_GREEN },
|
|
534
|
+
emojiContainer: {
|
|
535
|
+
height: 260,
|
|
536
|
+
backgroundColor: 'rgba(18,18,18,0.97)',
|
|
537
|
+
borderTopWidth: StyleSheet.hairlineWidth,
|
|
538
|
+
borderTopColor: 'rgba(255,255,255,0.10)',
|
|
539
|
+
},
|
|
540
|
+
emojiScroll: { flex: 1 },
|
|
541
|
+
emojiGrid: {
|
|
542
|
+
flexDirection: 'row',
|
|
543
|
+
flexWrap: 'wrap',
|
|
544
|
+
paddingHorizontal: 4,
|
|
545
|
+
paddingVertical: 8,
|
|
546
|
+
},
|
|
547
|
+
emojiCell: {
|
|
548
|
+
width: '12.5%',
|
|
549
|
+
aspectRatio: 1,
|
|
550
|
+
alignItems: 'center',
|
|
551
|
+
justifyContent: 'center',
|
|
552
|
+
},
|
|
553
|
+
emojiText: { fontSize: 26 },
|
|
491
554
|
});
|
package/package.json
CHANGED