// Import necessary dependencies
import React, { useState, useEffect } from 'react';
import { View, TouchableHighlight, StyleSheet, FlatList, TouchableWithoutFeedback, TouchableOpacity, Share, Dimensions, PixelRatio } from 'react-native';
import { Button, Text, ProgressBar } from 'react-native-paper';
import API from './../API.js';
import VideoPlayer from './VideoPlayer.js';
import VimeoPlayer from './VimeoPlayer.js';
import { WebView } from 'react-native-webview';
import { useSnapshot } from 'valtio';
import GlobalState from '../contexts/GlobalState.js';
import Moment from 'moment';
import { useNavigation } from '@react-navigation/native';
import { Image } from 'expo-image'; // Import Image from expo-image
import * as FileSystem from 'expo-file-system';
import * as Sharing from 'expo-sharing';
import i18n from "../i18nMessages.js";
// Extract Vimeo video ID from content string
const videoIdF = (content) => {
let vimeoTag = content.match(/@vimeo:[0-9]+/);
if (!vimeoTag) return [];
let tag = vimeoTag;
tag = tag[0].substring(1);
return tag.split(':');
};
// Extract YouTube video ID from content string
const youtubeIdF = (content) => {
// Accept classic 11-char IDs and common ID-safe chars.
let youtubeTag = content.match(/@youtube:([A-Za-z0-9_-]+)/);
if (!youtubeTag) return '';
return youtubeTag[1];
};
// Extract HLS URL from content string
const hlsIdF = (content) => {
let hslTag = content.match(/@hls:.+\w/);
if (!hslTag) return '';
let tag = hslTag;
tag = tag[0].substring(5);
return tag;
};
// Extract image tags from content string
const imagesTagF = (content, width = 1000, height = 1000) => {
let images = content.match(/@image:[0-z|/|.|]+/g);
if (!images) return [];
let Tags = [];
images.forEach(i => {
let tag = i.substring(1);
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
if (parts[1].substring(0, 4) != "http") parts[1] = `https://social.emmint.com/${parts[1]}?width=${width}&height=${height}`;
Tags.push(parts);
});
return Tags;
};
// Extract iframe source from content string
const iframeTagF = (content) => {
let iframeMatch = content.match(/@iframe:.+\w/g);
if (!iframeMatch) return [];
let tag = iframeMatch[0].substring(1);
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
return parts;
};
// Media Component
let Media = (props) => {
const gState = useSnapshot(GlobalState);
const viewer = gState.me;
// Extracting tags from content
const screenWidth = Dimensions.get('window').width;
const requestedImageWidth = props.imageWidth || Math.max(1200, Math.ceil(screenWidth * PixelRatio.get() * 1.2));
const requestedImageHeight = props.imageHeight || requestedImageWidth;
const imagesTag = imagesTagF(props.content, requestedImageWidth, requestedImageHeight);
const imagesTagLimited = imagesTag.slice(0, 10);
const isImagesCapped = imagesTag.length > imagesTagLimited.length;
const imageStyle = imagesTag.length === 1 ? styles.image : styles.multipleImage;
const videosId = videoIdF(props.content);
const hlsUrl = hlsIdF(props.content);
const iframeSrc = iframeTagF(props.content) || [];
const youtubeId = youtubeIdF(props.content);
const [videosFiles, setVideosFiles] = useState([]);
const [poster, setPoster] = useState('');
const [loaded, setLoaded] = useState(false);
const navigation = useNavigation();
let interactive = props.interactive || true;
// Fetch video data from API
useEffect(() => {
let subscribed = true;
let getData = async () => {
if (!videosId[1]) return;
let videoObj = await API.getVideo(videosId[1]);
if (videoObj && videoObj.files && subscribed) {
setVideosFiles(videoObj.files);
setPoster(videoObj.pictures.sizes[4].link);
}
};
getData();
return () => {
subscribed = false;
};
}, [props.content]);
// Render video component
const renderVideo = () => {
if (videosFiles.length && !props.skiptVideo) {
return loaded ? (
) : (
setLoaded(true)}>
);
}
if (videosId.length) {
return ;
}
return null;
};
// Render HLS video component
const renderHlsVideo = () => {
if (hlsUrl && !props.skiptVideo) {
return loaded ? (
) : (
{
GlobalState.currentMedia = hlsUrl;
GlobalState.mediaPost = props.post;
}}>
{poster ? (
) : (
)}
);
}
return null;
};
// Render iframe component
const renderIframe = () => {
if (iframeSrc.length) {
return (
);
}
return null;
};
// Render YouTube embed component
const renderYouTubeEmbed = () => {
if (youtubeId.length) {
return (
);
}
return null;
};
// Render progress bar if available
const renderProgressBar = () => {
if (viewer.data && viewer.data[props.postId]) {
const percent = Math.round(viewer.data[props.postId].time / viewer.data[props.postId].duration * 100);
if (percent) {
return (
<>
{percent}% {Moment(viewer.data[props.postId].ts).fromNow()}
>
);
}
}
return null;
};
// Function to share an image
const shareImage = async (imageUrl) => {
if (!interactive) return;
try {
// Download the image to the device's file system
const fileUri = `${FileSystem.cacheDirectory}shared-image.jpg`;
const { uri } = await FileSystem.downloadAsync(imageUrl, fileUri);
// Share the downloaded image
await Sharing.shareAsync(uri);
} catch (error) {
console.error("Error sharing the image", error);
}
};
// Function to handle navigation to slideshow
const navigateToSlideshow = (index) => {
if (!interactive) return;
navigation.navigate('Slideshow', { images: imagesTag, startIndex: index });
};
// Render images in a FlatList
const renderImages = ({ item, index }) => (
navigateToSlideshow(index)}
onLongPress={async () => {
await shareImage(item[1]);
}}
>
);
return (
{imagesTag.length > 2 ? (
<>
item[1]}
initialNumToRender={2}
style={{
transform: [{ scale: 1.1 }],
paddingTop: 5,
paddingBottom: 10,
}}
showsHorizontalScrollIndicator={false}
/>
{isImagesCapped ? (
navigateToSlideshow(0)} style={styles.seeAllPhotosWrap}>
{i18n.t("message.clickToSeeAllPhotos")}
) : <>>}
>
) : (
{imagesTag.map((image, i) => (
navigateToSlideshow(i)}
onLongPress={async () => {
await shareImage(image[1]);
}}
>
))}
)}
{renderVideo()}
{renderHlsVideo()}
{renderIframe()}
{renderYouTubeEmbed()}
{renderProgressBar()}
);
};
export default Media;
// Styles for different media components
const styles = StyleSheet.create({
image: {
width: "100%",
aspectRatio: 1,
borderRadius: 15,
},
poster: {
width: "100%",
aspectRatio: 9 / 6,
},
multipleImage: {
width: "49%",
aspectRatio: 1,
margin: 3,
borderRadius: 15,
},
flatlistImages: {
width: 300,
aspectRatio: 1,
margin: 5,
borderRadius: 15,
},
iframe: {
width: "100%",
minHeight: 300,
},
seeAllPhotosWrap: {
paddingTop: 2,
paddingBottom: 6,
paddingLeft: 6,
},
seeAllPhotosText: {
color: "#5f6368",
textDecorationLine: "underline",
fontSize: 13,
},
});