react-native-media-viewing
Version:
React Native modal component for viewing images and video as a sliding gallery
87 lines (86 loc) • 4.46 kB
JavaScript
/**
* Copyright (c) JOB TODAY S.A. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import React, { useCallback, useRef, useEffect } from "react";
import { Animated, Dimensions, StyleSheet, View, VirtualizedList, Modal, } from "react-native";
import MediaItem from "./components/MediaItem/MediaItem";
import MediaDefaultHeader from "./components/MediaDefaultHeader";
import StatusBarManager from "./components/StatusBarManager";
import useAnimatedComponents from "./hooks/useAnimatedComponents";
import useImageIndexChange from "./hooks/useImageIndexChange";
import useRequestClose from "./hooks/useRequestClose";
const DEFAULT_ANIMATION_TYPE = "fade";
const DEFAULT_BG_COLOR = "#000";
const DEFAULT_DELAY_LONG_PRESS = 800;
const SCREEN = Dimensions.get("screen");
const SCREEN_WIDTH = SCREEN.width;
function MediaViewing({ media, keyExtractor, imageIndex, visible, onRequestClose, onLongPress = () => { }, onImageIndexChange, animationType = DEFAULT_ANIMATION_TYPE, backgroundColor = DEFAULT_BG_COLOR, presentationStyle, swipeToCloseEnabled, doubleTapToZoomEnabled, delayLongPress = DEFAULT_DELAY_LONG_PRESS, HeaderComponent, FooterComponent, }) {
const imageList = useRef(null);
const [opacity, onRequestCloseEnhanced] = useRequestClose(onRequestClose);
const [currentImageIndex, onScroll] = useImageIndexChange(imageIndex, SCREEN);
const [headerTransform, footerTransform, toggleBarsVisible] = useAnimatedComponents();
useEffect(() => {
if (onImageIndexChange) {
onImageIndexChange(currentImageIndex);
}
}, [currentImageIndex]);
const onZoom = useCallback((isScaled) => {
var _a, _b;
// @ts-ignore
(_b = (_a = imageList) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.setNativeProps({ scrollEnabled: !isScaled });
toggleBarsVisible(!isScaled);
}, [imageList]);
if (!visible) {
return null;
}
return (<Modal transparent={presentationStyle === "overFullScreen"} visible={visible} presentationStyle={presentationStyle} animationType={animationType} onRequestClose={onRequestCloseEnhanced} supportedOrientations={["portrait"]} hardwareAccelerated>
<StatusBarManager presentationStyle={presentationStyle}/>
<View style={[styles.container, { opacity, backgroundColor }]}>
<Animated.View style={[styles.header, { transform: headerTransform }]}>
{typeof HeaderComponent !== "undefined" ? (React.createElement(HeaderComponent, {
imageIndex: currentImageIndex,
})) : (<MediaDefaultHeader onRequestClose={onRequestCloseEnhanced}/>)}
</Animated.View>
<VirtualizedList ref={imageList} data={media} horizontal pagingEnabled windowSize={2} initialNumToRender={1} maxToRenderPerBatch={1} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} initialScrollIndex={imageIndex} getItem={(_, index) => media[index]} getItemCount={() => media.length} getItemLayout={(_, index) => ({
length: SCREEN_WIDTH,
offset: SCREEN_WIDTH * index,
index,
})} renderItem={({ item: mediaSrc }) => (<MediaItem onZoom={onZoom} mediaSrc={mediaSrc} onRequestClose={onRequestCloseEnhanced} onLongPress={onLongPress} delayLongPress={delayLongPress} swipeToCloseEnabled={swipeToCloseEnabled} doubleTapToZoomEnabled={doubleTapToZoomEnabled}/>)} onMomentumScrollEnd={onScroll}
//@ts-ignore
keyExtractor={(mediaSrc, index) => keyExtractor
? keyExtractor(mediaSrc, index)
: typeof mediaSrc === "number"
? `${mediaSrc}`
: mediaSrc.uri}/>
{typeof FooterComponent !== "undefined" && (<Animated.View style={[styles.footer, { transform: footerTransform }]}>
{React.createElement(FooterComponent, {
imageIndex: currentImageIndex,
})}
</Animated.View>)}
</View>
</Modal>);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#000",
},
header: {
position: "absolute",
width: "100%",
zIndex: 1,
top: 0,
},
footer: {
position: "absolute",
width: "100%",
zIndex: 1,
bottom: 0,
},
});
const EnhancedMediaViewing = (props) => (<MediaViewing key={props.imageIndex} {...props}/>);
export default EnhancedMediaViewing;