const initialLayout = {width: Dimensions.get('window').width};
const LiveVideosRoute = () => { const [items, setItems] = useState([]); const [isFetching, setIsFetching] = useState(false); const [error, setError] = useState(false); const [playingIndex, setPlayingIndex] = useState(null); const [isFullScreen, setIsFullScreen] = useState(false); const [videoUrl, setVideoUrl] = useState(''); const [playing, setIsPlaying] = useState(false); const {userDetails} = useUser();
useEffect(() => { if (userDetails?.profileDetails.customer_id) { getCCTVDetails(); } else { setItems([]); } }, [userDetails?.profileDetails.customer_id]);
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('zone received 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);
}
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('zone received 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 renderItem = ({item, index}) => { const isPlaying = playingIndex === index;
return (
<TouchableOpacity
activeOpacity={1}
onPress={() => {
setIsPlaying(!playing);
if (!playing) {
setTimeout(() => {
setIsPlaying(false);
}, 3000);
}
}}
style={styles.listItemContainer}>
{item.rtsp_stream_url != null && (
<View style={styles.videoContainer}>
{!error ? (
<View>
<VLCPlayer
source={{
initType: 2,
hwDecoderEnabled: 1,
hwDecoderForced: 1,
uri: item.rtsp_stream_url,
}}
autoplay={false}
autoAspectRatio={true}
resizeMode="cover"
videoAspectRatio={'16:9'}
isLive={true}
autoReloadLive={true}
style={styles.videoPlayer}
paused={!isPlaying}
onError={() => setError(true)}
/>
<View style={styles.playButtonContainer}>
{isPlaying == false && (
<TouchableOpacity
onPress={() => {
if (playingIndex === index) {
setPlayingIndex(null);
setPlaying(false);
} else {
setPlayingIndex(index);
setPlaying(true);
}
}}>
<View style={styles.playButton}>
<Image source={PLAY} style={styles.playIcon} />
</View>
</TouchableOpacity>
)}
{isPlaying && playing && (
<TouchableOpacity
onPress={() => {
setPlayingIndex(null);
setPlaying(false);
}}>
<View style={styles.playButton}>
<Image source={HOME} style={styles.playIcon} />
</View>
</TouchableOpacity>
)}
</View>
</View>
) : (
<Text style={styles.videoUnavailableText}>
cctv video unavailable
</Text>
)}
</View>
)}
{!isFullScreen && (
<View style={styles.videoDetailsContainer}>
<Text style={styles.cameraName}>{item.name}</Text>
<TouchableOpacity
onPress={() => {
setVideoUrl(item.rtsp_stream_url);
handleFullScreenonPress();
}}>
<Image style={styles.fullScreenIcon} source={HOME} />
</TouchableOpacity>
</View>
)}
{isFullScreen && (
<TouchableOpacity
style={styles.fullScreenExitButton}
onPress={handleFullScreenonPress}>
<Image style={styles.fullScreenIcon} source={HOME} />
</TouchableOpacity>
)}
</TouchableOpacity>
);
return (
<TouchableOpacity
activeOpacity={1}
onPress={() => {
setIsPlaying(!playing);
if (!playing) {
setTimeout(() => {
setIsPlaying(false);
}, 3000);
}
}}
style={styles.listItemContainer}>
{item.rtsp_stream_url != null && (
<View style={styles.videoContainer}>
{!error ? (
<View>
<VLCPlayer
source={{
initType: 2,
hwDecoderEnabled: 1,
hwDecoderForced: 1,
uri: item.rtsp_stream_url,
}}
autoplay={false}
autoAspectRatio={true}
resizeMode="cover"
videoAspectRatio={'16:9'}
isLive={true}
autoReloadLive={true}
style={styles.videoPlayer}
paused={!isPlaying}
onError={() => setError(true)}
/>
<View style={styles.playButtonContainer}>
{isPlaying == false && (
<TouchableOpacity
onPress={() => {
if (playingIndex === index) {
setPlayingIndex(null);
setPlaying(false);
} else {
setPlayingIndex(index);
setPlaying(true);
}
}}>
<View style={styles.playButton}>
<Image source={PLAY} style={styles.playIcon} />
</View>
</TouchableOpacity>
)}
{isPlaying && playing && (
<TouchableOpacity
onPress={() => {
setPlayingIndex(null);
setPlaying(false);
}}>
<View style={styles.playButton}>
<Image source={HOME} style={styles.playIcon} />
</View>
</TouchableOpacity>
)}
</View>
</View>
) : (
<Text style={styles.videoUnavailableText}>
cctv video unavailable
</Text>
)}
</View>
)}
{!isFullScreen && (
<View style={styles.videoDetailsContainer}>
<Text style={styles.cameraName}>{item.name}</Text>
<TouchableOpacity
onPress={() => {
setVideoUrl(item.rtsp_stream_url);
handleFullScreenonPress();
}}>
<Image style={styles.fullScreenIcon} source={HOME} />
</TouchableOpacity>
</View>
)}
{isFullScreen && (
<TouchableOpacity
style={styles.fullScreenExitButton}
onPress={handleFullScreenonPress}>
<Image style={styles.fullScreenIcon} source={HOME} />
</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 live videos found.</Text>
</View>
);
}
return (
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
contentContainerStyle={ZoneScreenStyle.listContentContainer}
onRefresh={handleRefresh}
refreshing={isFetching}
/>
);
if (!isFetching && items.length === 0) {
return (
<View style={ZoneScreenStyle.centeredMessageContainer}>
<Text style={ZoneScreenStyle.messageText}>No live videos found.</Text>
</View>
);
}
return (
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
contentContainerStyle={ZoneScreenStyle.listContentContainer}
onRefresh={handleRefresh}
refreshing={isFetching}
/>
);
};
const handleFullScreenonPress = () => { if (isFullScreen == false) { setIsFullScreen(true); Orientation.lockToLandscape(); } else { setIsFullScreen(false); Orientation.lockToPortrait(); } };
return <View style={{flex: 1}}>{renderContent()}</View>; };
const PastVideosRoute = () => ( <View style={[ZoneScreenStyle.centeredMessageContainer, {backgroundColor: COLORS.white_color}]}> <Text style={ZoneScreenStyle.messageText}>Past Videos Content</Text> </View> );
const renderScene = SceneMap({ live: LiveVideosRoute, past: PastVideosRoute, });
const CCTVScreen = ({navigation}) => { const [index, setIndex] = useState(0); const [routes] = useState([ {key: 'live', title: 'Live Videos'}, {key: 'past', title: 'Past Videos'}, ]);
const renderTabBar = props => ( <TabBar {...props} indicatorStyle={{backgroundColor: COLORS.primary_color}} style={{backgroundColor: COLORS.white_color}} renderLabel={({route, focused, color}) => ( <Text style={{color: focused ? COLORS.primary_color : COLORS.grey_color, margin: 8, fontWeight: 'bold'}}> {route.title} </Text> )} /> );
return ( <TabView navigationState={{index, routes}} renderScene={renderScene} onIndexChange={setIndex} initialLayout={initialLayout} renderTabBar={renderTabBar} /> ); };
const styles = StyleSheet.create({ listItemContainer: { backgroundColor: COLORS.background_color, borderColor: COLORS.background_color, flex: 1, marginVertical: 8, marginHorizontal: 10, borderWidth: 1, borderRadius: 6, }, videoContainer: { borderTopLeftRadius: 6, borderTopRightRadius: 6, backgroundColor: COLORS.black_color, borderColor: COLORS.background_color, }, videoPlayer: { width: '100%', height: 200, }, playButtonContainer: { position: 'absolute', top: '50%', left: '50%', zIndex: 10, transform: [{translateX: -25}, {translateY: -25}], }, playButton: { width: 50, height: 50, backgroundColor: COLORS.white_color, borderRadius: 25, justifyContent: 'center', alignItems: 'center', }, playIcon: { height: 20, width: 20, }, videoUnavailableText: { paddingVertical: '25%', textAlign: 'center', color: COLORS.white_color }, videoDetailsContainer: { flexDirection: 'row', justifyContent: 'space-between', padding: 10, }, cameraName: { color: COLORS.text_color }, fullScreenIcon: { height: 20, width: 20, }, fullScreenExitButton: { position: 'absolute', top: 10, right: 10, }, });
export default CCTVScreen; _