import React, {useState, useEffect, useRef} from 'react';
import {
TouchableOpacity,
Text,
View,
FlatList,
Alert,
ActivityIndicator,
Image,
Dimensions,
StyleSheet,
BackHandler,
} from 'react-native';
import {useUser} from '../../context/UserContext';
import ApiManager from '../../services/ApiManager';
import ZoneScreenStyle from '../../styles/ZoneScreenStyle';
import {COLORS} from '../../styles/colors';
import {VLCPlayer} from 'react-native-vlc-media-player';
import {FULLSCREEN, HOME, NORMALSCREEN, PAUSE, PLAY} from '../../assets';
import Orientation from 'react-native-orientation-locker';
import {border_radius} from '../../styles/fontstyle';
import {useNavigation} from '@react-navigation/native';
const LiveCameraScreen = ({onFullScreenChange}) => {
const [items, setItems] = useState([]);
const [isFetching, setIsFetching] = useState(false);
const [errorIndex, setErrorIndex] = useState(null);
const [playingIndex, setPlayingIndex] = useState(null);
const [isFullScreen, setIsFullScreen] = useState(false);
const [currentFullScreenUrl, setCurrentFullScreenUrl] = useState('');
const navigation = useNavigation();
const vlcPlayers = useRef({});
const {userDetails} = useUser();
useEffect(() => {
if (userDetails?.profileDetails.customer_id) {
getCCTVDetails();
} else {
setItems([]);
}
}, [userDetails?.profileDetails.customer_id]); // Re-run only if customer_id changes
useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
if (isFullScreen) {
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
onFullScreenChange(false);
}
});
return unsubscribe;
}, [navigation, isFullScreen, onFullScreenChange]);
function handleBackButtonClick() {
Orientation.getOrientation(orientation => {
console.log('Current Orientation:', orientation);
if (orientation == 'LANDSCAPE-LEFT' || 'LANDSCAPE-RIGHT') {
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
onFullScreenChange(false);
return true;
}
});
}
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackButtonClick);
return () => {
BackHandler.removeEventListener(
'hardwareBackPress',
handleBackButtonClick,
);
};
}, []);
const getCCTVDetails = async (isManualRefresh = false) => {
if (!userDetails?.profileDetails.customer_id) {
console.log('User details not available yet or missing customer_id.');
setIsFetching(false);
return;
}
console.log(`Fetching list... Manual Refresh: ${isManualRefresh}`);
setIsFetching(true);
const customer_id = userDetails.profileDetails.customer_id;
try {
const listResponse = await ApiManager.getcctvDetails(customer_id);
console.log('camera listResponse:', listResponse);
if (listResponse) {
setItems(listResponse.Data.camerasList);
} else {
console.error(
'API did not return expected data structure:',
listResponse,
);
setItems([]);
if (isManualRefresh) {
Alert.alert(
'Error',
'Failed to fetch items. Invalid data format received.',
);
}
}
} catch (error) {
console.error('Fetch List Error in CommunityScreen:', error);
if (isManualRefresh) {
Alert.alert(
'Fetch Failed',
error.message || 'An unexpected error occurred while fetching items.',
);
}
setItems([]);
} finally {
setIsFetching(false);
}
};
const handleRefresh = () => {
getCCTVDetails(true);
};
const handlePlayPress = (index, url) => {
if (playingIndex === index) {
setPlayingIndex(null);
} else {
setPlayingIndex(index);
}
setErrorIndex(null); // Reset error when trying to play
};
const handleHomePress = url => {
if (!isFullScreen) {
setCurrentFullScreenUrl(url);
setIsFullScreen(true);
Orientation.lockToLandscape();
onFullScreenChange(true);
} else {
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
onFullScreenChange(false);
}
};
const handleVideoError = index => {
if (playingIndex === index) {
setPlayingIndex(null);
}
setErrorIndex(index);
console.log(`Error loading video at index: ${index}`);
// Optionally, you can show a specific error message to the user for this item.
};
const renderItem = ({item, index}) => {
const isPlaying = playingIndex === index;
const hasError = errorIndex === index;
return (
<TouchableOpacity
activeOpacity={1}
style={{
backgroundColor: COLORS.background_color,
borderColor: COLORS.background_color,
flex: 1,
marginVertical: !isFullScreen ? 8 : '',
marginHorizontal: !isFullScreen ? 10 : '',
borderWidth: 1,
borderRadius: 6,
}}>
{item.rtsp_stream_url != null && (
<View
style={{
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
backgroundColor: COLORS.black_color,
borderColor: COLORS.background_color,
}}>
{!hasError ? (
<View>
<VLCPlayer
ref={ref => (vlcPlayers.current[index] = ref)}
source={{
initType: 2,
hwDecoderEnabled: 1,
hwDecoderForced: 1,
uri: 'rtsp://admin:advaint101@192.168.1.90:554/ISAPI/Streaming/Channels/401',
}}
autoplay={false}
autoAspectRatio={true}
resizeMode="cover"
videoAspectRatio={'16:9'}
isLive={true}
autoReloadLive={true}
style={{
width: '100%',
height: isFullScreen
? Dimensions.get('window').height / 1.97
: 200,
borderRadius: border_radius.small,
}}
paused={!isPlaying}
onError={() => handleVideoError(index)}
/>
<View
style={{
position: 'absolute',
top: '50%',
left: '50%',
zIndex: 10,
transform: [{translateX: -25}, {translateY: -25}],
}}>
{isPlaying == false && (
<TouchableOpacity
onPress={() =>
handlePlayPress(index, item.rtsp_stream_url)
}>
<View style={styles.playButton}>
<Image source={PLAY} style={styles.playIcon} />
</View>
</TouchableOpacity>
)}
{isPlaying && (
<TouchableOpacity onPress={() => setPlayingIndex(null)}>
<View style={styles.homeButton}>
<Image source={PAUSE} style={styles.homeIcon} />
</View>
</TouchableOpacity>
)}
</View>
{!isFullScreen && (
<View style={styles.videoFooter}>
<Text style={styles.cameraName}>{item.name}</Text>
<TouchableOpacity
onPress={() => {
setCurrentFullScreenUrl(item.rtsp_stream_url);
setIsFullScreen(true);
Orientation.lockToLandscape();
onFullScreenChange(true);
}}>
<Image
style={styles.homeIconSmall}
source={NORMALSCREEN}
/>
</TouchableOpacity>
</View>
)}
</View>
) : (
<Text style={styles.errorText}>
CCTV video unavailable for {item.name}
</Text>
)}
</View>
)}
{isFullScreen && currentFullScreenUrl === item.rtsp_stream_url && (
<TouchableOpacity
style={styles.fullScreenCloseButton}
onPress={() => {
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
onFullScreenChange(false);
}}>
<Image style={styles.homeIcon} source={FULLSCREEN} />
</TouchableOpacity>
)}
</TouchableOpacity>
);
};
const renderContent = () => {
if (isFetching && items.length === 0) {
return (
<View style={ZoneScreenStyle.centeredMessageContainer}>
<ActivityIndicator size="large" color="#007bff" />
<Text style={ZoneScreenStyle.messageText}>Loading items...</Text>
</View>
);
}
if (!isFetching && items.length === 0) {
return (
<View style={ZoneScreenStyle.centeredMessageContainer}>
<Text style={ZoneScreenStyle.messageText}>
No community items found.
</Text>
</View>
);
}
return (
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
contentContainerStyle={ZoneScreenStyle.listContentContainer}
onRefresh={handleRefresh}
refreshing={isFetching}
/>
);
};
const handleFullScreenonPress = () => {
if (isFullScreen) {
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
onFullScreenChange(false);
}
};
return (
<View style={ZoneScreenStyle.safeArea}>
{isFullScreen == false && renderContent()}
{isFullScreen && currentFullScreenUrl !== '' && (
<View style={styles.fullScreenContainer}>
<VLCPlayer
source={{
initType: 2,
hwDecoderEnabled: 1,
hwDecoderForced: 1,
uri: 'rtsp://admin:advaint101@192.168.1.90:554/ISAPI/Streaming/Channels/401',
}}
autoplay={true}
autoAspectRatio={true}
resizeMode="cover"
videoAspectRatio={'16:9'}
isLive={true}
autoReloadLive={true}
style={styles.fullScreenVideo}
onError={() => {
Alert.alert('Error', 'Failed to play video in full screen.');
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
}}
/>
<TouchableOpacity
style={styles.fullScreenCloseButton}
onPress={handleFullScreenonPress}>
<Image style={styles.homeIcon} source={FULLSCREEN} />
</TouchableOpacity>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
playButton: {
width: 50,
height: 50,
backgroundColor: COLORS.white_color,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
},
playIcon: {
height: 20,
width: 20,
},
homeButton: {
width: 50,
height: 50,
backgroundColor: COLORS.white_color,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
},
homeIcon: {
height: 20,
width: 20,
tintColor: COLORS.black_color,
},
homeIconSmall: {
height: 20,
width: 20,
tintColor: COLORS.white_color,
},
videoFooter: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
position: 'absolute',
bottom: 2,
width: '100%',
},
cameraName: {
color: COLORS.white_color,
},
errorText: {
paddingVertical: '25%',
textAlign: 'center',
color: COLORS.error_color,
},
fullScreenContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: COLORS.black_color,
zIndex: 100,
justifyContent: 'center',
alignItems: 'center',
},
fullScreenVideo: {
width: '100%',
height: '100%',
},
fullScreenCloseButton: {
position: 'absolute',
top: 20,
right: 20,
zIndex: 101,
backgroundColor: 'rgba(0,0,0,0.5)',
borderRadius: 15,
width: 30,
height: 30,
justifyContent: 'center',
alignItems: 'center',
},
});
export default LiveCameraScreen;
whn I press NORMALSCREEN and set setIsFullScreen(true);
renderContent() should not render again & only
{isFullScreen && currentFullScreenUrl !== '' && (
<View style={styles.fullScreenContainer}>
<VLCPlayer
source={{
initType: 2,
hwDecoderEnabled: 1,
hwDecoderForced: 1,
uri: 'rtsp://admin:advaint101@192.168.1.90:554/ISAPI/Streaming/Channels/401',
}}
autoplay={true}
autoAspectRatio={true}
resizeMode="cover"
videoAspectRatio={'16:9'}
isLive={true}
autoReloadLive={true}
style={styles.fullScreenVideo}
onError={() => {
Alert.alert('Error', 'Failed to play video in full screen.');
setIsFullScreen(false);
Orientation.lockToPortrait();
setCurrentFullScreenUrl('');
}}
/>
<TouchableOpacity
style={styles.fullScreenCloseButton}
onPress={handleFullScreenonPress}>
<Image style={styles.homeIcon} source={FULLSCREEN} />
</TouchableOpacity>
</View>
)} should be visible with only single currentFullScreenUrl
make chnages and provide updated src folder