UNPKG

@cometchat/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

123 lines (120 loc) 4.64 kB
import React, { useRef, useState } from "react"; import { ActivityIndicator, Animated, Dimensions, Modal, PanResponder, Platform, StyleSheet, TouchableWithoutFeedback, View, } from "react-native"; import Video from "react-native-video"; import { Icon } from "../../icons/Icon"; export const CometChatVideoPlayer = (props) => { const { videoUri, isVisible, onClose, onLoad, loadingIconColor } = props; const [isPaused, setPaused] = useState(false); const [isLoading, setIsLoading] = useState(true); // Animated value for vertical position const pan = useRef(new Animated.ValueXY()).current; // Threshold for swipe-down to trigger close const SWIPE_THRESHOLD = 150; // PanResponder to handle swipe gestures const panResponder = useRef(PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: (_, gestureState) => { // Only respond to vertical gestures return Math.abs(gestureState.dy) > Math.abs(gestureState.dx); }, onPanResponderMove: Animated.event([null, { dy: pan.y }], { useNativeDriver: false }), onPanResponderRelease: (_, gestureState) => { if (gestureState.dy > SWIPE_THRESHOLD) { // User swiped down enough to dismiss Animated.timing(pan, { toValue: { x: 0, y: Dimensions.get("window").height }, duration: 200, useNativeDriver: false, }).start(() => { handleClose(); pan.setValue({ x: 0, y: 0 }); // Reset position }); } else { // Not enough swipe, reset position Animated.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: false, }).start(); } }, })).current; const handleLoadStart = () => { setIsLoading(true); setPaused(false); }; const handleBuffer = (bufferData) => { setIsLoading(bufferData.isBuffering); }; const handleLoad = () => { setIsLoading(false); onLoad(); }; /** * Closes the video (pauses it) and calls parent onClose. */ const handleClose = () => { setPaused(true); onClose(); }; return (<Modal animationType='fade' presentationStyle='overFullScreen' transparent={true} visible={isVisible} onRequestClose={handleClose}> <View style={styles.modalBackground}> <Animated.View style={[styles.overlay, { transform: [{ translateY: pan.y }] }]} {...panResponder.panHandlers}> <View style={styles.smallPlayerContainer}> <Video source={{ uri: videoUri }} controls={true} resizeMode='contain' onLoadStart={handleLoadStart} onBuffer={handleBuffer} onLoad={handleLoad} onError={(e) => console.warn("Video Error: ", e?.error)} paused={isPaused} style={styles.smallVideo}/> {isLoading && (<ActivityIndicator style={styles.loadingIndicator} size='large' color={loadingIconColor || "#fff"}/>)} {/* Optional: Custom close button */} <TouchableWithoutFeedback onPress={handleClose}> <View style={styles.closeButton}> <Icon name='close' size={18} color={"#fff"}/> </View> </TouchableWithoutFeedback> </View> </Animated.View> </View> </Modal>); }; const { width, height } = Dimensions.get("window"); const styles = StyleSheet.create({ modalBackground: { flex: 1, backgroundColor: "rgba(0,0,0,0.8)", justifyContent: "center", alignItems: "center", }, overlay: {}, smallPlayerContainer: { width: width * 0.95, height: height * 0.6, backgroundColor: "black", borderRadius: 10, overflow: "hidden", elevation: 5, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.8, shadowRadius: 2, }, smallVideo: { width: "100%", height: "100%", }, loadingIndicator: { position: "absolute", alignSelf: "center", top: "50%", }, closeButton: { position: "absolute", top: Platform.OS === "ios" ? 50 : 10, right: Platform.OS === "ios" ? 8 : 10, width: 30, height: 30, backgroundColor: "rgba(0,0,0,0.5)", borderRadius: 15, justifyContent: "center", alignItems: "center", zIndex: 1, }, }); //# sourceMappingURL=CometChatVideoPlayer.js.map