|
|
@@ -0,0 +1,121 @@
|
|
|
+import React from 'react';
|
|
|
+import { Modal, StyleSheet, View, TouchableOpacity, ActivityIndicator } from 'react-native';
|
|
|
+import ImageViewer from 'react-native-image-zoom-viewer';
|
|
|
+import { Colors } from 'src/theme';
|
|
|
+import CloseIcon from 'assets/icons/close.svg';
|
|
|
+
|
|
|
+interface Photo {
|
|
|
+ uri: string;
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+
|
|
|
+interface CustomImageViewerProps {
|
|
|
+ images: Photo[];
|
|
|
+ imageIndex: number;
|
|
|
+ visible: boolean;
|
|
|
+ onRequestClose: () => void;
|
|
|
+ backgroundColor?: string;
|
|
|
+ onImageIndexChange?: (index: number) => void;
|
|
|
+ renderFooter?: (currentIndex: number) => React.ReactElement;
|
|
|
+ loadingColor?: string;
|
|
|
+}
|
|
|
+
|
|
|
+export const CustomImageViewer: React.FC<CustomImageViewerProps> = ({
|
|
|
+ images,
|
|
|
+ imageIndex,
|
|
|
+ visible,
|
|
|
+ onRequestClose,
|
|
|
+ backgroundColor = Colors.DARK_BLUE,
|
|
|
+ onImageIndexChange,
|
|
|
+ renderFooter,
|
|
|
+ loadingColor = Colors.WHITE
|
|
|
+}) => {
|
|
|
+ const [currentIndex, setCurrentIndex] = React.useState(imageIndex);
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ setCurrentIndex(imageIndex);
|
|
|
+ }, [imageIndex]);
|
|
|
+
|
|
|
+ const handleIndexChange = (index?: number) => {
|
|
|
+ if (index !== undefined) {
|
|
|
+ setCurrentIndex(index);
|
|
|
+ onImageIndexChange?.(index);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const formattedImages = images.map((photo) => ({
|
|
|
+ url: photo.uri,
|
|
|
+ props: photo
|
|
|
+ }));
|
|
|
+
|
|
|
+ const footerRenderer = renderFooter
|
|
|
+ ? (currentIdx: number) => renderFooter(currentIdx)
|
|
|
+ : undefined;
|
|
|
+
|
|
|
+ const renderCloseButton = () => (
|
|
|
+ <TouchableOpacity
|
|
|
+ style={styles.closeButton}
|
|
|
+ onPress={onRequestClose}
|
|
|
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
|
+ >
|
|
|
+ <View style={styles.closeIconContainer}>
|
|
|
+ <CloseIcon fill={Colors.WHITE} height={16} width={16} />
|
|
|
+ </View>
|
|
|
+ </TouchableOpacity>
|
|
|
+ );
|
|
|
+
|
|
|
+ const renderLoadingIndicator = () => (
|
|
|
+ <View style={styles.loadingContainer}>
|
|
|
+ <ActivityIndicator size="large" color={loadingColor} />
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Modal visible={visible} transparent={true} onRequestClose={onRequestClose}>
|
|
|
+ <ImageViewer
|
|
|
+ imageUrls={formattedImages}
|
|
|
+ index={currentIndex}
|
|
|
+ onSwipeDown={onRequestClose}
|
|
|
+ enableSwipeDown
|
|
|
+ useNativeDriver
|
|
|
+ backgroundColor={backgroundColor}
|
|
|
+ onChange={handleIndexChange}
|
|
|
+ renderFooter={footerRenderer}
|
|
|
+ footerContainerStyle={styles.footerContainer}
|
|
|
+ renderIndicator={() => <View />}
|
|
|
+ onLongPress={() => null}
|
|
|
+ saveToLocalByLongPress={false}
|
|
|
+ enablePreload
|
|
|
+ loadingRender={renderLoadingIndicator}
|
|
|
+ renderHeader={renderCloseButton}
|
|
|
+ />
|
|
|
+ </Modal>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const styles = StyleSheet.create({
|
|
|
+ footerContainer: {
|
|
|
+ alignItems: 'center',
|
|
|
+ width: '100%'
|
|
|
+ },
|
|
|
+ closeButton: {
|
|
|
+ position: 'absolute',
|
|
|
+ top: 50,
|
|
|
+ right: 6,
|
|
|
+ zIndex: 1000,
|
|
|
+ padding: 8
|
|
|
+ },
|
|
|
+ closeIconContainer: {
|
|
|
+ width: 46,
|
|
|
+ height: 46,
|
|
|
+ borderRadius: 23,
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center',
|
|
|
+ backgroundColor: 'rgba(15, 63, 79, 0.7)'
|
|
|
+ },
|
|
|
+ loadingContainer: {
|
|
|
+ flex: 1,
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }
|
|
|
+});
|