@planningcenter/chat-react-native 3.12.0 → 3.12.1-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversation/attachments/image_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/image_attachment.js +15 -15
- package/build/components/conversation/attachments/image_attachment.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/attachments/image_attachment.tsx +51 -52
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image_attachment.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/image_attachment.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"image_attachment.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/image_attachment.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAA;AAgCvF,OAAO,EAAE,qCAAqC,EAAE,MAAM,2DAA2D,CAAA;AAuBjH,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,4BAA4B,GAC7B,EAAE;IACD,UAAU,EAAE,qCAAqC,CAAA;IACjD,gBAAgB,EAAE,qCAAqC,EAAE,CAAA;IACzD,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,SAAS,CAAA;IACpB,4BAA4B,EAAE,CAAC,UAAU,EAAE,qCAAqC,KAAK,IAAI,CAAA;CAC1F,qBAyCA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useMemo, useState, useCallback } from 'react';
|
|
2
|
-
import { StatusBar, StyleSheet, Modal, View, Linking, Dimensions,
|
|
2
|
+
import { StatusBar, StyleSheet, Modal, View, Linking, Dimensions, } from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
-
import { FlatList, Gesture, GestureDetector, GestureHandlerRootView,
|
|
4
|
+
import { FlatList, Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler';
|
|
5
5
|
import Animated, { runOnJS, useAnimatedStyle, useAnimatedReaction, useSharedValue, withSpring, withDecay, } from 'react-native-reanimated';
|
|
6
6
|
import { tokens } from '../../../vendor/tapestry/tokens';
|
|
7
7
|
import { IconButton, Image, Heading, Text } from '../../display';
|
|
@@ -14,7 +14,6 @@ const { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window');
|
|
|
14
14
|
const DISMISS_PAN_THRESHOLD = 250;
|
|
15
15
|
const MIN_DISTANCE_FOR_PAN = 10; // Higher threshold gives pinching priority
|
|
16
16
|
const SINGLE_FINGER_POINTER = 1; // Single-finger panning / tapping helps to avoid conflicts with pinching
|
|
17
|
-
const MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM = Platform.OS === 'ios' ? 8 : 0; // Causes taps to be unreliable on Android
|
|
18
17
|
const DEFAULT_OPACITY = 1;
|
|
19
18
|
const DEFAULT_TRANSLATE_X = 0;
|
|
20
19
|
const DEFAULT_TRANSLATE_Y = 0;
|
|
@@ -252,9 +251,6 @@ const LightboxModal = ({ visible, setModalVisible, imageAttachments, initialImag
|
|
|
252
251
|
lightboxToolbarVisible.value = withSpring(lightboxToolbarVisible.value > 0.5 ? 0 : 1, RESET_SPRING_CONFIG);
|
|
253
252
|
});
|
|
254
253
|
const doubleTapGesture = Gesture.Tap()
|
|
255
|
-
.maxDeltaX(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
256
|
-
.maxDeltaY(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
257
|
-
.maxDistance(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
258
254
|
.minPointers(SINGLE_FINGER_POINTER)
|
|
259
255
|
.numberOfTaps(2)
|
|
260
256
|
.onStart(e => {
|
|
@@ -448,22 +444,15 @@ const LightboxModal = ({ visible, setModalVisible, imageAttachments, initialImag
|
|
|
448
444
|
<StatusBar barStyle="light-content" hidden={isStatusBarHidden} animated showHideTransition="slide"/>
|
|
449
445
|
<GestureHandlerRootView>
|
|
450
446
|
<GestureDetector gesture={composedGesture}>
|
|
451
|
-
<
|
|
452
|
-
<FlatList data={imageAttachments} renderItem={({ item, index }) => (<GestureImage item={item} gesturesEnabled={index === currentImageIndex} scale={scale} translateX={translateX} translateY={translateY} dismissY={dismissY} opacity={opacity}/>)} keyExtractor={(item, index) => `${item.id}-${index}`} horizontal pagingEnabled scrollEnabled={flatListScrollEnabled} showsHorizontalScrollIndicator={false} initialScrollIndex={initialImageIndex} getItemLayout={getItemLayout} onMomentumScrollEnd={onMomentumScrollEnd} onViewableItemsChanged={onViewableItemsChanged} viewabilityConfig={{
|
|
447
|
+
<FlatList data={imageAttachments} renderItem={({ item, index }) => (<GestureImage item={item} gesturesEnabled={index === currentImageIndex} scale={scale} translateX={translateX} translateY={translateY} dismissY={dismissY} opacity={opacity}/>)} keyExtractor={(item, index) => `${item.id}-${index}`} horizontal pagingEnabled scrollEnabled={flatListScrollEnabled} showsHorizontalScrollIndicator={false} initialScrollIndex={initialImageIndex} getItemLayout={getItemLayout} onMomentumScrollEnd={onMomentumScrollEnd} onViewableItemsChanged={onViewableItemsChanged} viewabilityConfig={{
|
|
453
448
|
itemVisiblePercentThreshold: 50, // 50% of the image must be visible in the window to be considered viewable
|
|
454
449
|
}} style={styles.gallery} contentContainerStyle={styles.galleryContentContainer}/>
|
|
455
|
-
</PreventPressEventsBubbling>
|
|
456
450
|
</GestureDetector>
|
|
457
451
|
</GestureHandlerRootView>
|
|
458
452
|
<LightboxToolbarHeader metaProps={metaProps} lightboxToolbarVisible={lightboxToolbarVisible} isStatusBarHidden={isStatusBarHidden} handleOpenInBrowser={handleOpenInBrowser} handleCloseModal={handleCloseModal}/>
|
|
459
453
|
{imageAttachments.length > 1 && (<LightboxToolbarFooter lightboxToolbarVisible={lightboxToolbarVisible} totalImages={imageAttachments.length} currentImageIndex={currentImageIndex}/>)}
|
|
460
454
|
</Modal>);
|
|
461
455
|
};
|
|
462
|
-
const PreventPressEventsBubbling = ({ children }) => {
|
|
463
|
-
return (<Pressable onLongPress={() => { }} onPress={() => { }}>
|
|
464
|
-
{children}
|
|
465
|
-
</Pressable>);
|
|
466
|
-
};
|
|
467
456
|
const GestureImage = ({ item, gesturesEnabled, scale, translateX, translateY, dismissY, opacity, }) => {
|
|
468
457
|
const styles = useStyles();
|
|
469
458
|
const { url: itemUrl, urlMedium: itemUrlMedium } = item.attributes;
|
|
@@ -477,7 +466,15 @@ const GestureImage = ({ item, gesturesEnabled, scale, translateX, translateY, di
|
|
|
477
466
|
opacity: opacity.value,
|
|
478
467
|
};
|
|
479
468
|
});
|
|
480
|
-
return (<
|
|
469
|
+
return (<TouchEventIsolator>
|
|
470
|
+
<Image source={{ uri: itemUrlMedium || itemUrl }} style={styles.gestureImage} animatedImageStyle={animatedImageStyles} loadingBackgroundStyles={styles.gestureImageLoading} resizeMode="contain" alt=""/>
|
|
471
|
+
</TouchEventIsolator>);
|
|
472
|
+
};
|
|
473
|
+
const TouchEventIsolator = ({ children }) => {
|
|
474
|
+
const styles = useStyles();
|
|
475
|
+
return (<View style={styles.touchEventIsolator} onStartShouldSetResponder={() => true}>
|
|
476
|
+
{children}
|
|
477
|
+
</View>);
|
|
481
478
|
};
|
|
482
479
|
const LightboxToolbarHeader = ({ metaProps, lightboxToolbarVisible, isStatusBarHidden, handleOpenInBrowser, handleCloseModal, }) => {
|
|
483
480
|
const styles = useStyles();
|
|
@@ -523,6 +520,9 @@ const useStyles = ({ imageWidth = 100, imageHeight = 100 } = {}) => {
|
|
|
523
520
|
container: {
|
|
524
521
|
maxWidth: '100%',
|
|
525
522
|
},
|
|
523
|
+
touchEventIsolator: {
|
|
524
|
+
flex: 1,
|
|
525
|
+
},
|
|
526
526
|
attachmentImageWrapper: {
|
|
527
527
|
width: '100%',
|
|
528
528
|
minWidth: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image_attachment.js","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/image_attachment.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useMemo, useState, Dispatch, SetStateAction, useCallback } from 'react'\nimport {\n StatusBar,\n StyleSheet,\n Modal,\n View,\n Linking,\n Dimensions,\n NativeSyntheticEvent,\n NativeScrollEvent,\n ViewToken,\n Platform,\n} from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport {\n FlatList,\n Gesture,\n GestureDetector,\n GestureHandlerRootView,\n Pressable,\n} from 'react-native-gesture-handler'\nimport Animated, {\n runOnJS,\n useAnimatedStyle,\n useAnimatedReaction,\n useSharedValue,\n withSpring,\n withDecay,\n SharedValue,\n} from 'react-native-reanimated'\nimport { tokens } from '../../../vendor/tapestry/tokens'\nimport { IconButton, Image, Heading, Text } from '../../display'\nimport colorFunction from 'color'\nimport { formatDatePreview } from '../../../utils/date'\nimport { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'\nimport { PlatformPressable } from '@react-navigation/elements'\nimport { useTheme } from '../../../hooks'\nimport { platformFontWeightMedium } from '../../../utils'\n\nconst { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window')\nconst DISMISS_PAN_THRESHOLD = 250\nconst MIN_DISTANCE_FOR_PAN = 10 // Higher threshold gives pinching priority\nconst SINGLE_FINGER_POINTER = 1 // Single-finger panning / tapping helps to avoid conflicts with pinching\nconst MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM = Platform.OS === 'ios' ? 8 : 0 // Causes taps to be unreliable on Android\nconst DEFAULT_OPACITY = 1\nconst DEFAULT_TRANSLATE_X = 0\nconst DEFAULT_TRANSLATE_Y = 0\nconst DEFAULT_SCALE = 1\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 5\nconst MAX_SCALE_OVERSHOOT = 5\nconst DOUBLE_TAP_ZOOM_SCALE = 2\nconst DECAY_VELOCITY_FACTOR = 0.4\nconst RESET_SPRING_CONFIG = {\n damping: 20,\n stiffness: 150,\n}\n\nexport type MetaProps = {\n authorName: string\n createdAt: string\n}\n\nexport function ImageAttachment({\n attachment,\n imageAttachments,\n currentImageIndex,\n metaProps,\n onMessageAttachmentLongPress,\n}: {\n attachment: DenormalizedMessageAttachmentResource\n imageAttachments: DenormalizedMessageAttachmentResource[]\n currentImageIndex: number\n metaProps: MetaProps\n onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void\n}) {\n const { attributes } = attachment\n const { url, urlMedium, filename, metadata = {} } = attributes\n const { colors } = useTheme()\n\n const styles = useStyles({ imageWidth: metadata.width, imageHeight: metadata.height })\n const [visible, setVisible] = useState(false)\n\n // Force modal to remount with fresh state\n // Fixes a bug where dismissing the modal too quickly causes the Reanimated shared values (like toolbarVisible) to not reset.\n const [modalKey, setModalKey] = useState(0)\n\n return (\n <>\n <PlatformPressable\n style={styles.container}\n onPress={() => {\n setModalKey(prev => prev + 1)\n setVisible(true)\n }}\n onLongPress={() => onMessageAttachmentLongPress(attachment)}\n android_ripple={{ color: colors.androidRippleNeutral, foreground: true }}\n accessibilityHint=\"Long press for more options\"\n >\n <Image\n source={{ uri: urlMedium || url }}\n style={styles.image}\n wrapperStyle={styles.attachmentImageWrapper}\n alt={filename}\n />\n </PlatformPressable>\n <LightboxModal\n key={modalKey}\n visible={visible}\n setModalVisible={setVisible}\n imageAttachments={imageAttachments}\n initialImageIndex={currentImageIndex}\n metaProps={metaProps}\n />\n </>\n )\n}\n\ninterface LightboxModalProps {\n visible: boolean\n setModalVisible: Dispatch<SetStateAction<boolean>>\n imageAttachments: DenormalizedMessageAttachmentResource[]\n initialImageIndex: number\n metaProps: MetaProps\n}\n\nconst LightboxModal = ({\n visible,\n setModalVisible,\n imageAttachments,\n initialImageIndex,\n metaProps,\n}: LightboxModalProps) => {\n const styles = useStyles()\n const insets = useSafeAreaInsets()\n const [currentImageIndex, setCurrentImageIndex] = useState(initialImageIndex)\n\n // Get current image data\n const currentImage = imageAttachments[currentImageIndex]\n const { url, urlMedium, metadata = {} } = currentImage.attributes\n const imageWidth = metadata.width\n const imageHeight = metadata.height\n\n // Calculate available space for image display\n const availableWindowWidth = WINDOW_WIDTH\n const availableWindowHeight = WINDOW_HEIGHT - insets.top - insets.bottom\n\n /* ============================\n ANIMATION VALUES\n ============================ */\n // Native State:\n const dismissY = useSharedValue(0) // vertical distance to dismiss modal\n const opacity = useSharedValue(DEFAULT_OPACITY) // opacity of modal\n const scale = useSharedValue(DEFAULT_SCALE) // zoom level of image\n const focalX = useSharedValue(0) // focal point of image between fingers\n const focalY = useSharedValue(0) // focal point of image between fingers\n const translateX = useSharedValue(DEFAULT_TRANSLATE_X) // horizontal distance to pan image\n const translateY = useSharedValue(DEFAULT_TRANSLATE_Y) // vertical distance to pan image\n const savedScale = useSharedValue(DEFAULT_SCALE) // previous zoom level\n const savedTranslateX = useSharedValue(DEFAULT_TRANSLATE_X) // previous horizontal position\n const savedTranslateY = useSharedValue(DEFAULT_TRANSLATE_Y) // previous vertical position\n const lightboxToolbarVisible = useSharedValue(1) // toolbar visibility state\n\n // React (JS) State:\n const [isStatusBarHidden, setIsStatusBarHidden] = useState(false)\n const [flatListScrollEnabled, setFlatListScrollEnabled] = useState(true)\n const [panGestureEnabled, setPanGestureEnabled] = useState(false)\n\n // Syncs toolbar useSharedValue state with React's state so that the status bar can be hidden/shown based on the toolbar's animation\n useAnimatedReaction(\n () => lightboxToolbarVisible.value,\n value => {\n runOnJS(setIsStatusBarHidden)(value === 0)\n }\n )\n\n // Syncs FlatList scroll state with scale changes\n // When image is at default scale, enable scroll and disable pan gesture\n // When image is zoomed in, disable scroll and enable pan gesture\n useAnimatedReaction(\n () => scale.value,\n value => {\n const enableFlatListScroll = value === DEFAULT_SCALE\n runOnJS(setFlatListScrollEnabled)(enableFlatListScroll)\n runOnJS(setPanGestureEnabled)(!enableFlatListScroll)\n }\n )\n\n /* ============================\n HANDLERS\n ============================ */\n const handleOpenInBrowser = useCallback(() => {\n Linking.openURL(urlMedium || url)\n }, [urlMedium, url])\n\n const resetDismissGestures = useCallback(() => {\n dismissY.value = withSpring(0, RESET_SPRING_CONFIG)\n opacity.value = withSpring(DEFAULT_OPACITY, RESET_SPRING_CONFIG)\n }, [dismissY, opacity])\n\n const resetAllGestures = useCallback(() => {\n resetDismissGestures()\n scale.value = withSpring(DEFAULT_SCALE, RESET_SPRING_CONFIG)\n translateX.value = withSpring(DEFAULT_TRANSLATE_X, RESET_SPRING_CONFIG)\n translateY.value = withSpring(DEFAULT_TRANSLATE_Y, RESET_SPRING_CONFIG)\n savedScale.value = DEFAULT_SCALE\n savedTranslateX.value = DEFAULT_TRANSLATE_X\n savedTranslateY.value = DEFAULT_TRANSLATE_Y\n lightboxToolbarVisible.value = withSpring(1, RESET_SPRING_CONFIG)\n }, [\n resetDismissGestures,\n scale,\n translateX,\n translateY,\n savedScale,\n savedTranslateX,\n savedTranslateY,\n lightboxToolbarVisible,\n ])\n\n const handleCloseModal = useCallback(() => {\n setModalVisible(false)\n resetAllGestures()\n }, [setModalVisible, resetAllGestures])\n\n /* ============================\n UTILITY WORKLET FUNCTIONS\n 'worklet' runs functions on the UI thread, instead of the JS thread for better performance.\n ============================ */\n const getImageContainedToWindowDimensions = () => {\n 'worklet'\n\n if (!imageWidth || !imageHeight) {\n return { width: availableWindowWidth, height: availableWindowHeight }\n }\n\n const imageAspectRatio = imageWidth / imageHeight\n const windowAspectRatio = availableWindowWidth / availableWindowHeight\n\n // Constrain image width if its wider than window\n if (imageAspectRatio > windowAspectRatio) {\n return {\n width: availableWindowWidth,\n height: availableWindowWidth / imageAspectRatio,\n }\n }\n\n // Constrain image height if its taller than window\n return {\n width: availableWindowHeight * imageAspectRatio,\n height: availableWindowHeight,\n }\n }\n\n const zoomToFocalPoint = ({\n focalPointX,\n focalPointY,\n targetScale,\n currentSavedScale,\n currentSavedTranslateX,\n currentSavedTranslateY,\n }: {\n focalPointX: number\n focalPointY: number\n targetScale: number\n currentSavedScale: number\n currentSavedTranslateX: number\n currentSavedTranslateY: number\n }) => {\n 'worklet'\n\n // How far the focal point is from the center of the window\n const windowCenterX = WINDOW_WIDTH / 2\n const windowCenterY = WINDOW_HEIGHT / 2\n\n // Position of focal point relative to current image position\n const focalRelativeX = focalPointX - windowCenterX - currentSavedTranslateX\n const focalRelativeY = focalPointY - windowCenterY - currentSavedTranslateY\n\n // Calculate new translation to keep focal point under fingers\n const scaleRatio = targetScale / currentSavedScale\n const newTranslateX = currentSavedTranslateX + focalRelativeX * (1 - scaleRatio)\n const newTranslateY = currentSavedTranslateY + focalRelativeY * (1 - scaleRatio)\n\n return {\n translateX: newTranslateX,\n translateY: newTranslateY,\n }\n }\n\n const getMaxTranslationLimits = (currentScale: number) => {\n 'worklet'\n\n const { width: containedImageWidth, height: containedImageHeight } =\n getImageContainedToWindowDimensions()\n\n // Image dimensions after scaling/zooming\n const scaledWidth = containedImageWidth * currentScale\n const scaledHeight = containedImageHeight * currentScale\n\n // How much the scaled image exceeds the window container\n const excessWidth = scaledWidth - availableWindowWidth\n const excessHeight = scaledHeight - availableWindowHeight\n\n // How far the image can move in each direction before hitting window edges\n const maxTranslateX = Math.max(DEFAULT_TRANSLATE_X, excessWidth / 2)\n const maxTranslateY = Math.max(DEFAULT_TRANSLATE_Y, excessHeight / 2)\n\n return { maxTranslateX, maxTranslateY }\n }\n\n const clampDecay = (currentScale: number): { x: [number, number]; y: [number, number] } => {\n 'worklet'\n\n const { maxTranslateX, maxTranslateY } = getMaxTranslationLimits(currentScale)\n\n return {\n x: [-maxTranslateX, maxTranslateX],\n y: [-maxTranslateY, maxTranslateY],\n }\n }\n\n const clampTranslation = ({\n x,\n y,\n currentScale,\n }: {\n x: number\n y: number\n currentScale: number\n }) => {\n 'worklet'\n\n const { maxTranslateX, maxTranslateY } = getMaxTranslationLimits(currentScale)\n\n return {\n x: Math.min(maxTranslateX, Math.max(-maxTranslateX, x)),\n y: Math.min(maxTranslateY, Math.max(-maxTranslateY, y)),\n }\n }\n\n const isImageAtVerticalBoundry = (currentScale: number) => {\n 'worklet'\n\n const { height: containedImageHeight } = getImageContainedToWindowDimensions()\n\n // Calculate how much the image can exceed the window container\n const scaledHeight = containedImageHeight * currentScale\n const excessHeight = scaledHeight - availableWindowHeight\n const maxTranslateY = Math.max(DEFAULT_TRANSLATE_Y, excessHeight / 2)\n\n const currentTranslateY = translateY.value\n const panPositionTolerance = 1 // buffer to account for translateY being at a subpixel position\n\n const atTopBoundry = currentTranslateY >= maxTranslateY - panPositionTolerance\n const atBottomBoundry = currentTranslateY <= -maxTranslateY + panPositionTolerance\n\n return atTopBoundry || atBottomBoundry\n }\n\n /* ============================\n UTILITY FLATLIST FUNCTIONS\n Supports the image gallery layout and swipe functionality.\n ============================ */\n\n // Used in tandem with FlatList's initialScrollIndex to quickly calculate the position and size of each image before they load.\n const getItemLayout = useCallback(\n (_: unknown, index: number) => ({\n length: WINDOW_WIDTH,\n offset: WINDOW_WIDTH * index,\n index,\n }),\n []\n )\n\n // Captures the current image's index after the FlatList finishes its scroll animation.\n // Used in tandem with onViewableItemsChanged to ensure the final value for currentImageIndex is set.\n const onMomentumScrollEnd = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n // Calculate the index of the image that is currently visible\n const imageOffsetX = event.nativeEvent.contentOffset.x\n const newImageIndex = Math.round(imageOffsetX / WINDOW_WIDTH)\n\n // Check if the image index has changed and the FlatList didn't scroll past the first or last image\n const didImageIndexChange = newImageIndex !== currentImageIndex\n const isImageIndexWithinBounds = newImageIndex >= 0 && newImageIndex < imageAttachments.length\n\n if (didImageIndexChange && isImageIndexWithinBounds) {\n setCurrentImageIndex(newImageIndex)\n }\n },\n [currentImageIndex, imageAttachments.length]\n )\n\n // Supplements onMomentumScrollEnd by capturing the current image's index while the FlatList is actively scrolling.\n // Used in tandem with viewabilityConfig to trigger when the image is 50% visible in the window.\n const onViewableItemsChanged = useCallback(\n ({ viewableItems }: { viewableItems: ViewToken<DenormalizedMessageAttachmentResource>[] }) => {\n if (viewableItems.length === 0) return\n\n // Use the first viewable item which is enforced by the FlatList's pagingEnabled prop that allows only two images to be visible at a time when scrolling.\n const firstViewableItem = viewableItems[0]\n const newIndex = firstViewableItem.index\n\n if (newIndex !== null && newIndex !== currentImageIndex) {\n setCurrentImageIndex(newIndex)\n }\n },\n [currentImageIndex]\n )\n\n /* ============================\n GESTURES\n ============================ */\n const singleTapGesture = Gesture.Tap()\n .minPointers(SINGLE_FINGER_POINTER)\n .numberOfTaps(1)\n .onStart(() => {\n lightboxToolbarVisible.value = withSpring(\n lightboxToolbarVisible.value > 0.5 ? 0 : 1,\n RESET_SPRING_CONFIG\n )\n })\n\n const doubleTapGesture = Gesture.Tap()\n .maxDeltaX(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)\n .maxDeltaY(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)\n .maxDistance(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)\n .minPointers(SINGLE_FINGER_POINTER)\n .numberOfTaps(2)\n .onStart(e => {\n const isZoomedIn = scale.value > DEFAULT_SCALE\n if (isZoomedIn) {\n runOnJS(resetAllGestures)()\n } else {\n // Hide toolbar when starting to zoom\n lightboxToolbarVisible.value = withSpring(0, RESET_SPRING_CONFIG)\n\n // Zoom to 2x at tap location\n const newTranslation = zoomToFocalPoint({\n focalPointX: e.x,\n focalPointY: e.y,\n targetScale: DOUBLE_TAP_ZOOM_SCALE,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Apply clamping to ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslation.translateX,\n y: newTranslation.translateY,\n currentScale: DOUBLE_TAP_ZOOM_SCALE,\n })\n\n // Animate to new scale and translation\n scale.value = withSpring(DOUBLE_TAP_ZOOM_SCALE, RESET_SPRING_CONFIG)\n translateX.value = withSpring(clampedTranslate.x, RESET_SPRING_CONFIG)\n translateY.value = withSpring(clampedTranslate.y, RESET_SPRING_CONFIG)\n\n // Update saved state for next gesture\n savedScale.value = DOUBLE_TAP_ZOOM_SCALE\n savedTranslateX.value = clampedTranslate.x\n savedTranslateY.value = clampedTranslate.y\n }\n })\n\n const pinchGesture = Gesture.Pinch()\n .onStart(e => {\n focalX.value = e.focalX\n focalY.value = e.focalY\n\n // Hide toolbar when starting to zoom\n lightboxToolbarVisible.value = withSpring(0, RESET_SPRING_CONFIG)\n\n // Ensure that pinch accounts for the decay animation and starts from the true current position.\n savedTranslateX.value = translateX.value\n savedTranslateY.value = translateY.value\n })\n .onUpdate(e => {\n // Zoom image in/out within scale limits\n const newScale = savedScale.value * e.scale\n const newScaleClamped = Math.min(\n MAX_SCALE + MAX_SCALE_OVERSHOOT,\n Math.max(MIN_SCALE, newScale)\n )\n scale.value = newScaleClamped\n\n // Calculate new translation to keep focal point under fingers\n const newTranslation = zoomToFocalPoint({\n focalPointX: focalX.value,\n focalPointY: focalY.value,\n targetScale: newScaleClamped,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Apply translation without clamping to ensure focal point doesn't jump during gesture\n translateX.value = newTranslation.translateX\n translateY.value = newTranslation.translateY\n })\n .onEnd(() => {\n const currentScale = scale.value\n\n // Dismiss modal if fully zoomed out\n if (currentScale <= MIN_SCALE) {\n runOnJS(handleCloseModal)()\n return\n }\n\n // Reset all gestures if image is near default scale\n const isNearDefaultScale = currentScale <= DEFAULT_SCALE + 0.1\n if (isNearDefaultScale) {\n runOnJS(resetAllGestures)()\n return\n }\n\n // Check if overshooting the max scale and clamp it\n const finalScale = currentScale > MAX_SCALE ? MAX_SCALE : currentScale\n\n // Recalculate translation using focal point to always return to the same position when image is overshooting the max scale\n const newTranslation = zoomToFocalPoint({\n focalPointX: focalX.value,\n focalPointY: focalY.value,\n targetScale: finalScale,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslation.translateX,\n y: newTranslation.translateY,\n currentScale: finalScale,\n })\n\n // Animate to position and scale limits with a spring\n scale.value = withSpring(finalScale, RESET_SPRING_CONFIG)\n translateX.value = withSpring(clampedTranslate.x, RESET_SPRING_CONFIG)\n translateY.value = withSpring(clampedTranslate.y, RESET_SPRING_CONFIG)\n\n // Save state for next gesture\n savedScale.value = finalScale\n savedTranslateX.value = clampedTranslate.x\n savedTranslateY.value = clampedTranslate.y\n })\n\n const panGesture = Gesture.Pan()\n .minDistance(MIN_DISTANCE_FOR_PAN)\n .minPointers(SINGLE_FINGER_POINTER)\n .maxPointers(SINGLE_FINGER_POINTER)\n .enabled(panGestureEnabled)\n .onStart(() => {\n // Update saved position to current animated position\n // This ensures smooth continuation if decay is running\n savedTranslateX.value = translateX.value\n savedTranslateY.value = translateY.value\n })\n .onUpdate(e => {\n // Only pan if image is zoomed in\n if (scale.value <= DEFAULT_SCALE) return\n\n const newTranslateX = savedTranslateX.value + e.translationX\n const newTranslateY = savedTranslateY.value + e.translationY\n\n // Ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslateX,\n y: newTranslateY,\n currentScale: scale.value,\n })\n translateX.value = clampedTranslate.x\n translateY.value = clampedTranslate.y\n })\n .onEnd(e => {\n // Prevents saving pan position if image is zoomed out while panning\n if (scale.value <= DEFAULT_SCALE) return\n\n const clampDecayBounds = clampDecay(scale.value)\n\n translateX.value = withDecay(\n {\n velocity: e.velocityX * DECAY_VELOCITY_FACTOR,\n clamp: clampDecayBounds.x,\n deceleration: 0.996,\n },\n finished => {\n if (finished) {\n savedTranslateX.value = translateX.value\n }\n }\n )\n\n translateY.value = withDecay(\n {\n velocity: e.velocityY * DECAY_VELOCITY_FACTOR,\n clamp: clampDecayBounds.y,\n deceleration: 0.996,\n },\n finished => {\n if (finished) {\n savedTranslateY.value = translateY.value\n }\n }\n )\n })\n\n const panToDismissModalGesture = Gesture.Pan()\n .onUpdate(e => {\n const atDefaultScale = scale.value === DEFAULT_SCALE\n\n // Calculate zoom conditions for dismissing modal\n const atVerticalBoundry = isImageAtVerticalBoundry(scale.value)\n const panDirectionIsPrimarilyVertical = Math.abs(e.translationY) > Math.abs(e.translationX)\n const canDismissWhileZoomed = atVerticalBoundry && panDirectionIsPrimarilyVertical\n\n if (!(atDefaultScale || canDismissWhileZoomed)) return\n\n // Fade image if its been panned past 50% of the dismiss threshold\n const panDistance = Math.abs(e.translationY)\n const halfThreshold = DISMISS_PAN_THRESHOLD / 2\n const fadeDistance = Math.max(0, panDistance - halfThreshold)\n const fadeProgress = fadeDistance / halfThreshold\n\n opacity.value = Math.max(0, DEFAULT_OPACITY - fadeProgress)\n dismissY.value = e.translationY\n })\n .onEnd(() => {\n const exceededDismissThreshold = Math.abs(dismissY.value) > DISMISS_PAN_THRESHOLD\n\n if (exceededDismissThreshold) {\n runOnJS(handleCloseModal)()\n } else {\n runOnJS(resetDismissGestures)()\n }\n })\n\n /* ==============================\n COMPOSE GESTURES\n ================================= */\n // Race between pinch and pan ensures only one is active at a time, preserving focal point logic\n const pinchOrPanGestures = Gesture.Race(pinchGesture, panGesture)\n\n // Exclusive race ensures single tap doesn't interfere with double tap\n const tapGestures = Gesture.Exclusive(doubleTapGesture, singleTapGesture)\n\n // Race between tap gestures and pinch/pan\n const transformImageGestures = Gesture.Race(tapGestures, pinchOrPanGestures)\n\n // Dismiss can work simultaneously with all gestures\n const composedGesture = Gesture.Simultaneous(transformImageGestures, panToDismissModalGesture)\n\n return (\n <Modal visible={visible} transparent animationType=\"fade\" onRequestClose={handleCloseModal}>\n <StatusBar\n barStyle=\"light-content\"\n hidden={isStatusBarHidden}\n animated\n showHideTransition=\"slide\"\n />\n <GestureHandlerRootView>\n <GestureDetector gesture={composedGesture}>\n <PreventPressEventsBubbling>\n <FlatList\n data={imageAttachments}\n renderItem={({ item, index }) => (\n <GestureImage\n item={item}\n gesturesEnabled={index === currentImageIndex}\n scale={scale}\n translateX={translateX}\n translateY={translateY}\n dismissY={dismissY}\n opacity={opacity}\n />\n )}\n keyExtractor={(item, index) => `${item.id}-${index}`}\n horizontal\n pagingEnabled\n scrollEnabled={flatListScrollEnabled}\n showsHorizontalScrollIndicator={false}\n initialScrollIndex={initialImageIndex}\n getItemLayout={getItemLayout}\n onMomentumScrollEnd={onMomentumScrollEnd}\n onViewableItemsChanged={onViewableItemsChanged}\n viewabilityConfig={{\n itemVisiblePercentThreshold: 50, // 50% of the image must be visible in the window to be considered viewable\n }}\n style={styles.gallery}\n contentContainerStyle={styles.galleryContentContainer}\n />\n </PreventPressEventsBubbling>\n </GestureDetector>\n </GestureHandlerRootView>\n <LightboxToolbarHeader\n metaProps={metaProps}\n lightboxToolbarVisible={lightboxToolbarVisible}\n isStatusBarHidden={isStatusBarHidden}\n handleOpenInBrowser={handleOpenInBrowser}\n handleCloseModal={handleCloseModal}\n />\n {imageAttachments.length > 1 && (\n <LightboxToolbarFooter\n lightboxToolbarVisible={lightboxToolbarVisible}\n totalImages={imageAttachments.length}\n currentImageIndex={currentImageIndex}\n />\n )}\n </Modal>\n )\n}\n\nconst PreventPressEventsBubbling = ({ children }: { children: React.ReactNode }) => {\n return (\n <Pressable onLongPress={() => {}} onPress={() => {}}>\n {children}\n </Pressable>\n )\n}\n\ninterface GestureImageProps {\n item: DenormalizedMessageAttachmentResource\n gesturesEnabled: boolean\n scale: SharedValue<number>\n translateX: SharedValue<number>\n translateY: SharedValue<number>\n dismissY: SharedValue<number>\n opacity: SharedValue<number>\n}\n\nconst GestureImage = ({\n item,\n gesturesEnabled,\n scale,\n translateX,\n translateY,\n dismissY,\n opacity,\n}: GestureImageProps) => {\n const styles = useStyles()\n const { url: itemUrl, urlMedium: itemUrlMedium } = item.attributes\n\n const animatedImageStyles = useAnimatedStyle(() => {\n return {\n transform: [\n { translateX: gesturesEnabled ? translateX.value : DEFAULT_TRANSLATE_X },\n { translateY: gesturesEnabled ? translateY.value + dismissY.value : DEFAULT_TRANSLATE_Y },\n { scale: gesturesEnabled ? scale.value : DEFAULT_SCALE },\n ],\n opacity: opacity.value,\n }\n })\n\n return (\n <Image\n source={{ uri: itemUrlMedium || itemUrl }}\n style={styles.gestureImage}\n animatedImageStyle={animatedImageStyles}\n loadingBackgroundStyles={styles.gestureImageLoading}\n resizeMode=\"contain\"\n alt=\"\"\n />\n )\n}\n\ninterface LightboxToolbarHeaderProps {\n metaProps: MetaProps\n lightboxToolbarVisible: SharedValue<number>\n isStatusBarHidden: boolean\n handleOpenInBrowser: () => void\n handleCloseModal: () => void\n}\n\nconst LightboxToolbarHeader = ({\n metaProps,\n lightboxToolbarVisible,\n isStatusBarHidden,\n handleOpenInBrowser,\n handleCloseModal,\n}: LightboxToolbarHeaderProps) => {\n const styles = useStyles()\n const { authorName, createdAt } = metaProps\n\n const animatedHeaderStyles = useAnimatedStyle(() => ({\n opacity: lightboxToolbarVisible.value,\n transform: [\n { translateY: (1 - lightboxToolbarVisible.value) * -20 }, // slide up when hiding\n ],\n }))\n\n return (\n <Animated.View\n style={[styles.lightboxToolbar, styles.lightboxToolbarHeader, animatedHeaderStyles]}\n accessibilityRole=\"toolbar\"\n >\n <View style={styles.lightboxToolbarHeaderMetaContainer}>\n <Heading variant=\"h3\" style={styles.lightboxToolbarHeaderTitle} numberOfLines={1}>\n {authorName}\n </Heading>\n <Text variant=\"tertiary\" style={styles.lightboxToolbarHeaderSubtitle}>\n {formatDatePreview(createdAt)}\n </Text>\n </View>\n <IconButton\n onPress={handleOpenInBrowser}\n disabled={isStatusBarHidden}\n name=\"general.newWindow\"\n accessibilityRole=\"link\"\n accessibilityLabel=\"Open image in browser\"\n accessibilityHint=\"Image can be downloaded and shared through the browser.\"\n style={styles.lightboxToolbarButton}\n iconStyle={styles.lightboxToolbarButtonIcon}\n size=\"lg\"\n />\n <IconButton\n onPress={handleCloseModal}\n disabled={isStatusBarHidden}\n name=\"general.x\"\n accessibilityLabel=\"Close image\"\n style={styles.lightboxToolbarButton}\n iconStyle={styles.lightboxToolbarButtonIcon}\n size=\"lg\"\n />\n </Animated.View>\n )\n}\n\ninterface LightboxToolbarFooterProps {\n lightboxToolbarVisible: SharedValue<number>\n totalImages: number\n currentImageIndex: number\n}\n\nconst LightboxToolbarFooter = ({\n lightboxToolbarVisible,\n totalImages,\n currentImageIndex,\n}: LightboxToolbarFooterProps) => {\n const styles = useStyles()\n\n const animatedFooterStyles = useAnimatedStyle(() => ({\n opacity: lightboxToolbarVisible.value,\n transform: [\n { translateY: (1 - lightboxToolbarVisible.value) * 20 }, // slide down when showing\n ],\n }))\n\n return (\n <Animated.View\n style={[styles.lightboxToolbar, styles.lightboxToolbarFooter, animatedFooterStyles]}\n accessibilityRole=\"toolbar\"\n >\n <Text style={styles.lightboxToolbarFooterText}>\n {currentImageIndex + 1} of {totalImages}\n </Text>\n </Animated.View>\n )\n}\n\ninterface UseStylesProps {\n imageWidth?: number\n imageHeight?: number\n}\n\nconst useStyles = ({ imageWidth = 100, imageHeight = 100 }: UseStylesProps = {}) => {\n const { top, bottom } = useSafeAreaInsets()\n const backgroundColor = tokens.colorNeutral7\n const transparentBackgroundColor = useMemo(\n () => colorFunction(backgroundColor).alpha(0.8).toString(),\n [backgroundColor]\n )\n\n return StyleSheet.create({\n container: {\n maxWidth: '100%',\n },\n attachmentImageWrapper: {\n width: '100%',\n minWidth: 200,\n aspectRatio: imageWidth / imageHeight,\n },\n image: {\n borderRadius: 8,\n },\n gallery: {\n backgroundColor,\n },\n galleryContentContainer: {\n paddingTop: top,\n paddingBottom: bottom,\n },\n gestureImage: {\n height: '100%',\n width: WINDOW_WIDTH,\n backgroundColor: 'transparent',\n },\n gestureImageLoading: {\n backgroundColor,\n },\n lightboxToolbar: {\n width: '100%',\n position: 'absolute',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 20,\n paddingHorizontal: 16,\n backgroundColor: transparentBackgroundColor,\n },\n lightboxToolbarButton: {\n backgroundColor,\n height: 40,\n width: 40,\n borderRadius: 50,\n borderWidth: 1,\n borderColor: tokens.colorNeutral24,\n },\n lightboxToolbarButtonIcon: {\n color: tokens.colorNeutral88,\n },\n lightboxToolbarHeader: {\n top: 0,\n paddingTop: top + 16,\n paddingBottom: 8,\n },\n lightboxToolbarHeaderMetaContainer: {\n flex: 1,\n },\n lightboxToolbarHeaderTitle: {\n marginRight: 'auto',\n flexShrink: 1,\n color: tokens.colorNeutral88,\n },\n lightboxToolbarHeaderSubtitle: {\n color: tokens.colorNeutral68,\n },\n lightboxToolbarFooter: {\n justifyContent: 'center',\n bottom: 0,\n paddingTop: 8,\n paddingBottom: bottom + 16,\n },\n lightboxToolbarFooterText: {\n color: tokens.colorNeutral88,\n fontWeight: platformFontWeightMedium,\n },\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"image_attachment.js","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/image_attachment.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useMemo, useState, Dispatch, SetStateAction, useCallback } from 'react'\nimport {\n StatusBar,\n StyleSheet,\n Modal,\n View,\n Linking,\n Dimensions,\n NativeSyntheticEvent,\n NativeScrollEvent,\n ViewToken,\n} from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport {\n FlatList,\n Gesture,\n GestureDetector,\n GestureHandlerRootView,\n} from 'react-native-gesture-handler'\nimport Animated, {\n runOnJS,\n useAnimatedStyle,\n useAnimatedReaction,\n useSharedValue,\n withSpring,\n withDecay,\n SharedValue,\n} from 'react-native-reanimated'\nimport { tokens } from '../../../vendor/tapestry/tokens'\nimport { IconButton, Image, Heading, Text } from '../../display'\nimport colorFunction from 'color'\nimport { formatDatePreview } from '../../../utils/date'\nimport { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'\nimport { PlatformPressable } from '@react-navigation/elements'\nimport { useTheme } from '../../../hooks'\nimport { platformFontWeightMedium } from '../../../utils'\n\nconst { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window')\nconst DISMISS_PAN_THRESHOLD = 250\nconst MIN_DISTANCE_FOR_PAN = 10 // Higher threshold gives pinching priority\nconst SINGLE_FINGER_POINTER = 1 // Single-finger panning / tapping helps to avoid conflicts with pinching\nconst DEFAULT_OPACITY = 1\nconst DEFAULT_TRANSLATE_X = 0\nconst DEFAULT_TRANSLATE_Y = 0\nconst DEFAULT_SCALE = 1\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 5\nconst MAX_SCALE_OVERSHOOT = 5\nconst DOUBLE_TAP_ZOOM_SCALE = 2\nconst DECAY_VELOCITY_FACTOR = 0.4\nconst RESET_SPRING_CONFIG = {\n damping: 20,\n stiffness: 150,\n}\n\nexport type MetaProps = {\n authorName: string\n createdAt: string\n}\n\nexport function ImageAttachment({\n attachment,\n imageAttachments,\n currentImageIndex,\n metaProps,\n onMessageAttachmentLongPress,\n}: {\n attachment: DenormalizedMessageAttachmentResource\n imageAttachments: DenormalizedMessageAttachmentResource[]\n currentImageIndex: number\n metaProps: MetaProps\n onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void\n}) {\n const { attributes } = attachment\n const { url, urlMedium, filename, metadata = {} } = attributes\n const { colors } = useTheme()\n\n const styles = useStyles({ imageWidth: metadata.width, imageHeight: metadata.height })\n const [visible, setVisible] = useState(false)\n\n // Force modal to remount with fresh state\n // Fixes a bug where dismissing the modal too quickly causes the Reanimated shared values (like toolbarVisible) to not reset.\n const [modalKey, setModalKey] = useState(0)\n\n return (\n <>\n <PlatformPressable\n style={styles.container}\n onPress={() => {\n setModalKey(prev => prev + 1)\n setVisible(true)\n }}\n onLongPress={() => onMessageAttachmentLongPress(attachment)}\n android_ripple={{ color: colors.androidRippleNeutral, foreground: true }}\n accessibilityHint=\"Long press for more options\"\n >\n <Image\n source={{ uri: urlMedium || url }}\n style={styles.image}\n wrapperStyle={styles.attachmentImageWrapper}\n alt={filename}\n />\n </PlatformPressable>\n <LightboxModal\n key={modalKey}\n visible={visible}\n setModalVisible={setVisible}\n imageAttachments={imageAttachments}\n initialImageIndex={currentImageIndex}\n metaProps={metaProps}\n />\n </>\n )\n}\n\ninterface LightboxModalProps {\n visible: boolean\n setModalVisible: Dispatch<SetStateAction<boolean>>\n imageAttachments: DenormalizedMessageAttachmentResource[]\n initialImageIndex: number\n metaProps: MetaProps\n}\n\nconst LightboxModal = ({\n visible,\n setModalVisible,\n imageAttachments,\n initialImageIndex,\n metaProps,\n}: LightboxModalProps) => {\n const styles = useStyles()\n const insets = useSafeAreaInsets()\n const [currentImageIndex, setCurrentImageIndex] = useState(initialImageIndex)\n\n // Get current image data\n const currentImage = imageAttachments[currentImageIndex]\n const { url, urlMedium, metadata = {} } = currentImage.attributes\n const imageWidth = metadata.width\n const imageHeight = metadata.height\n\n // Calculate available space for image display\n const availableWindowWidth = WINDOW_WIDTH\n const availableWindowHeight = WINDOW_HEIGHT - insets.top - insets.bottom\n\n /* ============================\n ANIMATION VALUES\n ============================ */\n // Native State:\n const dismissY = useSharedValue(0) // vertical distance to dismiss modal\n const opacity = useSharedValue(DEFAULT_OPACITY) // opacity of modal\n const scale = useSharedValue(DEFAULT_SCALE) // zoom level of image\n const focalX = useSharedValue(0) // focal point of image between fingers\n const focalY = useSharedValue(0) // focal point of image between fingers\n const translateX = useSharedValue(DEFAULT_TRANSLATE_X) // horizontal distance to pan image\n const translateY = useSharedValue(DEFAULT_TRANSLATE_Y) // vertical distance to pan image\n const savedScale = useSharedValue(DEFAULT_SCALE) // previous zoom level\n const savedTranslateX = useSharedValue(DEFAULT_TRANSLATE_X) // previous horizontal position\n const savedTranslateY = useSharedValue(DEFAULT_TRANSLATE_Y) // previous vertical position\n const lightboxToolbarVisible = useSharedValue(1) // toolbar visibility state\n\n // React (JS) State:\n const [isStatusBarHidden, setIsStatusBarHidden] = useState(false)\n const [flatListScrollEnabled, setFlatListScrollEnabled] = useState(true)\n const [panGestureEnabled, setPanGestureEnabled] = useState(false)\n\n // Syncs toolbar useSharedValue state with React's state so that the status bar can be hidden/shown based on the toolbar's animation\n useAnimatedReaction(\n () => lightboxToolbarVisible.value,\n value => {\n runOnJS(setIsStatusBarHidden)(value === 0)\n }\n )\n\n // Syncs FlatList scroll state with scale changes\n // When image is at default scale, enable scroll and disable pan gesture\n // When image is zoomed in, disable scroll and enable pan gesture\n useAnimatedReaction(\n () => scale.value,\n value => {\n const enableFlatListScroll = value === DEFAULT_SCALE\n runOnJS(setFlatListScrollEnabled)(enableFlatListScroll)\n runOnJS(setPanGestureEnabled)(!enableFlatListScroll)\n }\n )\n\n /* ============================\n HANDLERS\n ============================ */\n const handleOpenInBrowser = useCallback(() => {\n Linking.openURL(urlMedium || url)\n }, [urlMedium, url])\n\n const resetDismissGestures = useCallback(() => {\n dismissY.value = withSpring(0, RESET_SPRING_CONFIG)\n opacity.value = withSpring(DEFAULT_OPACITY, RESET_SPRING_CONFIG)\n }, [dismissY, opacity])\n\n const resetAllGestures = useCallback(() => {\n resetDismissGestures()\n scale.value = withSpring(DEFAULT_SCALE, RESET_SPRING_CONFIG)\n translateX.value = withSpring(DEFAULT_TRANSLATE_X, RESET_SPRING_CONFIG)\n translateY.value = withSpring(DEFAULT_TRANSLATE_Y, RESET_SPRING_CONFIG)\n savedScale.value = DEFAULT_SCALE\n savedTranslateX.value = DEFAULT_TRANSLATE_X\n savedTranslateY.value = DEFAULT_TRANSLATE_Y\n lightboxToolbarVisible.value = withSpring(1, RESET_SPRING_CONFIG)\n }, [\n resetDismissGestures,\n scale,\n translateX,\n translateY,\n savedScale,\n savedTranslateX,\n savedTranslateY,\n lightboxToolbarVisible,\n ])\n\n const handleCloseModal = useCallback(() => {\n setModalVisible(false)\n resetAllGestures()\n }, [setModalVisible, resetAllGestures])\n\n /* ============================\n UTILITY WORKLET FUNCTIONS\n 'worklet' runs functions on the UI thread, instead of the JS thread for better performance.\n ============================ */\n const getImageContainedToWindowDimensions = () => {\n 'worklet'\n\n if (!imageWidth || !imageHeight) {\n return { width: availableWindowWidth, height: availableWindowHeight }\n }\n\n const imageAspectRatio = imageWidth / imageHeight\n const windowAspectRatio = availableWindowWidth / availableWindowHeight\n\n // Constrain image width if its wider than window\n if (imageAspectRatio > windowAspectRatio) {\n return {\n width: availableWindowWidth,\n height: availableWindowWidth / imageAspectRatio,\n }\n }\n\n // Constrain image height if its taller than window\n return {\n width: availableWindowHeight * imageAspectRatio,\n height: availableWindowHeight,\n }\n }\n\n const zoomToFocalPoint = ({\n focalPointX,\n focalPointY,\n targetScale,\n currentSavedScale,\n currentSavedTranslateX,\n currentSavedTranslateY,\n }: {\n focalPointX: number\n focalPointY: number\n targetScale: number\n currentSavedScale: number\n currentSavedTranslateX: number\n currentSavedTranslateY: number\n }) => {\n 'worklet'\n\n // How far the focal point is from the center of the window\n const windowCenterX = WINDOW_WIDTH / 2\n const windowCenterY = WINDOW_HEIGHT / 2\n\n // Position of focal point relative to current image position\n const focalRelativeX = focalPointX - windowCenterX - currentSavedTranslateX\n const focalRelativeY = focalPointY - windowCenterY - currentSavedTranslateY\n\n // Calculate new translation to keep focal point under fingers\n const scaleRatio = targetScale / currentSavedScale\n const newTranslateX = currentSavedTranslateX + focalRelativeX * (1 - scaleRatio)\n const newTranslateY = currentSavedTranslateY + focalRelativeY * (1 - scaleRatio)\n\n return {\n translateX: newTranslateX,\n translateY: newTranslateY,\n }\n }\n\n const getMaxTranslationLimits = (currentScale: number) => {\n 'worklet'\n\n const { width: containedImageWidth, height: containedImageHeight } =\n getImageContainedToWindowDimensions()\n\n // Image dimensions after scaling/zooming\n const scaledWidth = containedImageWidth * currentScale\n const scaledHeight = containedImageHeight * currentScale\n\n // How much the scaled image exceeds the window container\n const excessWidth = scaledWidth - availableWindowWidth\n const excessHeight = scaledHeight - availableWindowHeight\n\n // How far the image can move in each direction before hitting window edges\n const maxTranslateX = Math.max(DEFAULT_TRANSLATE_X, excessWidth / 2)\n const maxTranslateY = Math.max(DEFAULT_TRANSLATE_Y, excessHeight / 2)\n\n return { maxTranslateX, maxTranslateY }\n }\n\n const clampDecay = (currentScale: number): { x: [number, number]; y: [number, number] } => {\n 'worklet'\n\n const { maxTranslateX, maxTranslateY } = getMaxTranslationLimits(currentScale)\n\n return {\n x: [-maxTranslateX, maxTranslateX],\n y: [-maxTranslateY, maxTranslateY],\n }\n }\n\n const clampTranslation = ({\n x,\n y,\n currentScale,\n }: {\n x: number\n y: number\n currentScale: number\n }) => {\n 'worklet'\n\n const { maxTranslateX, maxTranslateY } = getMaxTranslationLimits(currentScale)\n\n return {\n x: Math.min(maxTranslateX, Math.max(-maxTranslateX, x)),\n y: Math.min(maxTranslateY, Math.max(-maxTranslateY, y)),\n }\n }\n\n const isImageAtVerticalBoundry = (currentScale: number) => {\n 'worklet'\n\n const { height: containedImageHeight } = getImageContainedToWindowDimensions()\n\n // Calculate how much the image can exceed the window container\n const scaledHeight = containedImageHeight * currentScale\n const excessHeight = scaledHeight - availableWindowHeight\n const maxTranslateY = Math.max(DEFAULT_TRANSLATE_Y, excessHeight / 2)\n\n const currentTranslateY = translateY.value\n const panPositionTolerance = 1 // buffer to account for translateY being at a subpixel position\n\n const atTopBoundry = currentTranslateY >= maxTranslateY - panPositionTolerance\n const atBottomBoundry = currentTranslateY <= -maxTranslateY + panPositionTolerance\n\n return atTopBoundry || atBottomBoundry\n }\n\n /* ============================\n UTILITY FLATLIST FUNCTIONS\n Supports the image gallery layout and swipe functionality.\n ============================ */\n\n // Used in tandem with FlatList's initialScrollIndex to quickly calculate the position and size of each image before they load.\n const getItemLayout = useCallback(\n (_: unknown, index: number) => ({\n length: WINDOW_WIDTH,\n offset: WINDOW_WIDTH * index,\n index,\n }),\n []\n )\n\n // Captures the current image's index after the FlatList finishes its scroll animation.\n // Used in tandem with onViewableItemsChanged to ensure the final value for currentImageIndex is set.\n const onMomentumScrollEnd = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n // Calculate the index of the image that is currently visible\n const imageOffsetX = event.nativeEvent.contentOffset.x\n const newImageIndex = Math.round(imageOffsetX / WINDOW_WIDTH)\n\n // Check if the image index has changed and the FlatList didn't scroll past the first or last image\n const didImageIndexChange = newImageIndex !== currentImageIndex\n const isImageIndexWithinBounds = newImageIndex >= 0 && newImageIndex < imageAttachments.length\n\n if (didImageIndexChange && isImageIndexWithinBounds) {\n setCurrentImageIndex(newImageIndex)\n }\n },\n [currentImageIndex, imageAttachments.length]\n )\n\n // Supplements onMomentumScrollEnd by capturing the current image's index while the FlatList is actively scrolling.\n // Used in tandem with viewabilityConfig to trigger when the image is 50% visible in the window.\n const onViewableItemsChanged = useCallback(\n ({ viewableItems }: { viewableItems: ViewToken<DenormalizedMessageAttachmentResource>[] }) => {\n if (viewableItems.length === 0) return\n\n // Use the first viewable item which is enforced by the FlatList's pagingEnabled prop that allows only two images to be visible at a time when scrolling.\n const firstViewableItem = viewableItems[0]\n const newIndex = firstViewableItem.index\n\n if (newIndex !== null && newIndex !== currentImageIndex) {\n setCurrentImageIndex(newIndex)\n }\n },\n [currentImageIndex]\n )\n\n /* ============================\n GESTURES\n ============================ */\n const singleTapGesture = Gesture.Tap()\n .minPointers(SINGLE_FINGER_POINTER)\n .numberOfTaps(1)\n .onStart(() => {\n lightboxToolbarVisible.value = withSpring(\n lightboxToolbarVisible.value > 0.5 ? 0 : 1,\n RESET_SPRING_CONFIG\n )\n })\n\n const doubleTapGesture = Gesture.Tap()\n .minPointers(SINGLE_FINGER_POINTER)\n .numberOfTaps(2)\n .onStart(e => {\n const isZoomedIn = scale.value > DEFAULT_SCALE\n if (isZoomedIn) {\n runOnJS(resetAllGestures)()\n } else {\n // Hide toolbar when starting to zoom\n lightboxToolbarVisible.value = withSpring(0, RESET_SPRING_CONFIG)\n\n // Zoom to 2x at tap location\n const newTranslation = zoomToFocalPoint({\n focalPointX: e.x,\n focalPointY: e.y,\n targetScale: DOUBLE_TAP_ZOOM_SCALE,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Apply clamping to ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslation.translateX,\n y: newTranslation.translateY,\n currentScale: DOUBLE_TAP_ZOOM_SCALE,\n })\n\n // Animate to new scale and translation\n scale.value = withSpring(DOUBLE_TAP_ZOOM_SCALE, RESET_SPRING_CONFIG)\n translateX.value = withSpring(clampedTranslate.x, RESET_SPRING_CONFIG)\n translateY.value = withSpring(clampedTranslate.y, RESET_SPRING_CONFIG)\n\n // Update saved state for next gesture\n savedScale.value = DOUBLE_TAP_ZOOM_SCALE\n savedTranslateX.value = clampedTranslate.x\n savedTranslateY.value = clampedTranslate.y\n }\n })\n\n const pinchGesture = Gesture.Pinch()\n .onStart(e => {\n focalX.value = e.focalX\n focalY.value = e.focalY\n\n // Hide toolbar when starting to zoom\n lightboxToolbarVisible.value = withSpring(0, RESET_SPRING_CONFIG)\n\n // Ensure that pinch accounts for the decay animation and starts from the true current position.\n savedTranslateX.value = translateX.value\n savedTranslateY.value = translateY.value\n })\n .onUpdate(e => {\n // Zoom image in/out within scale limits\n const newScale = savedScale.value * e.scale\n const newScaleClamped = Math.min(\n MAX_SCALE + MAX_SCALE_OVERSHOOT,\n Math.max(MIN_SCALE, newScale)\n )\n scale.value = newScaleClamped\n\n // Calculate new translation to keep focal point under fingers\n const newTranslation = zoomToFocalPoint({\n focalPointX: focalX.value,\n focalPointY: focalY.value,\n targetScale: newScaleClamped,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Apply translation without clamping to ensure focal point doesn't jump during gesture\n translateX.value = newTranslation.translateX\n translateY.value = newTranslation.translateY\n })\n .onEnd(() => {\n const currentScale = scale.value\n\n // Dismiss modal if fully zoomed out\n if (currentScale <= MIN_SCALE) {\n runOnJS(handleCloseModal)()\n return\n }\n\n // Reset all gestures if image is near default scale\n const isNearDefaultScale = currentScale <= DEFAULT_SCALE + 0.1\n if (isNearDefaultScale) {\n runOnJS(resetAllGestures)()\n return\n }\n\n // Check if overshooting the max scale and clamp it\n const finalScale = currentScale > MAX_SCALE ? MAX_SCALE : currentScale\n\n // Recalculate translation using focal point to always return to the same position when image is overshooting the max scale\n const newTranslation = zoomToFocalPoint({\n focalPointX: focalX.value,\n focalPointY: focalY.value,\n targetScale: finalScale,\n currentSavedScale: savedScale.value,\n currentSavedTranslateX: savedTranslateX.value,\n currentSavedTranslateY: savedTranslateY.value,\n })\n\n // Ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslation.translateX,\n y: newTranslation.translateY,\n currentScale: finalScale,\n })\n\n // Animate to position and scale limits with a spring\n scale.value = withSpring(finalScale, RESET_SPRING_CONFIG)\n translateX.value = withSpring(clampedTranslate.x, RESET_SPRING_CONFIG)\n translateY.value = withSpring(clampedTranslate.y, RESET_SPRING_CONFIG)\n\n // Save state for next gesture\n savedScale.value = finalScale\n savedTranslateX.value = clampedTranslate.x\n savedTranslateY.value = clampedTranslate.y\n })\n\n const panGesture = Gesture.Pan()\n .minDistance(MIN_DISTANCE_FOR_PAN)\n .minPointers(SINGLE_FINGER_POINTER)\n .maxPointers(SINGLE_FINGER_POINTER)\n .enabled(panGestureEnabled)\n .onStart(() => {\n // Update saved position to current animated position\n // This ensures smooth continuation if decay is running\n savedTranslateX.value = translateX.value\n savedTranslateY.value = translateY.value\n })\n .onUpdate(e => {\n // Only pan if image is zoomed in\n if (scale.value <= DEFAULT_SCALE) return\n\n const newTranslateX = savedTranslateX.value + e.translationX\n const newTranslateY = savedTranslateY.value + e.translationY\n\n // Ensure image edges remain within window boundaries\n const clampedTranslate = clampTranslation({\n x: newTranslateX,\n y: newTranslateY,\n currentScale: scale.value,\n })\n translateX.value = clampedTranslate.x\n translateY.value = clampedTranslate.y\n })\n .onEnd(e => {\n // Prevents saving pan position if image is zoomed out while panning\n if (scale.value <= DEFAULT_SCALE) return\n\n const clampDecayBounds = clampDecay(scale.value)\n\n translateX.value = withDecay(\n {\n velocity: e.velocityX * DECAY_VELOCITY_FACTOR,\n clamp: clampDecayBounds.x,\n deceleration: 0.996,\n },\n finished => {\n if (finished) {\n savedTranslateX.value = translateX.value\n }\n }\n )\n\n translateY.value = withDecay(\n {\n velocity: e.velocityY * DECAY_VELOCITY_FACTOR,\n clamp: clampDecayBounds.y,\n deceleration: 0.996,\n },\n finished => {\n if (finished) {\n savedTranslateY.value = translateY.value\n }\n }\n )\n })\n\n const panToDismissModalGesture = Gesture.Pan()\n .onUpdate(e => {\n const atDefaultScale = scale.value === DEFAULT_SCALE\n\n // Calculate zoom conditions for dismissing modal\n const atVerticalBoundry = isImageAtVerticalBoundry(scale.value)\n const panDirectionIsPrimarilyVertical = Math.abs(e.translationY) > Math.abs(e.translationX)\n const canDismissWhileZoomed = atVerticalBoundry && panDirectionIsPrimarilyVertical\n\n if (!(atDefaultScale || canDismissWhileZoomed)) return\n\n // Fade image if its been panned past 50% of the dismiss threshold\n const panDistance = Math.abs(e.translationY)\n const halfThreshold = DISMISS_PAN_THRESHOLD / 2\n const fadeDistance = Math.max(0, panDistance - halfThreshold)\n const fadeProgress = fadeDistance / halfThreshold\n\n opacity.value = Math.max(0, DEFAULT_OPACITY - fadeProgress)\n dismissY.value = e.translationY\n })\n .onEnd(() => {\n const exceededDismissThreshold = Math.abs(dismissY.value) > DISMISS_PAN_THRESHOLD\n\n if (exceededDismissThreshold) {\n runOnJS(handleCloseModal)()\n } else {\n runOnJS(resetDismissGestures)()\n }\n })\n\n /* ==============================\n COMPOSE GESTURES\n ================================= */\n // Race between pinch and pan ensures only one is active at a time, preserving focal point logic\n const pinchOrPanGestures = Gesture.Race(pinchGesture, panGesture)\n\n // Exclusive race ensures single tap doesn't interfere with double tap\n const tapGestures = Gesture.Exclusive(doubleTapGesture, singleTapGesture)\n\n // Race between tap gestures and pinch/pan\n const transformImageGestures = Gesture.Race(tapGestures, pinchOrPanGestures)\n\n // Dismiss can work simultaneously with all gestures\n const composedGesture = Gesture.Simultaneous(transformImageGestures, panToDismissModalGesture)\n\n return (\n <Modal visible={visible} transparent animationType=\"fade\" onRequestClose={handleCloseModal}>\n <StatusBar\n barStyle=\"light-content\"\n hidden={isStatusBarHidden}\n animated\n showHideTransition=\"slide\"\n />\n <GestureHandlerRootView>\n <GestureDetector gesture={composedGesture}>\n <FlatList\n data={imageAttachments}\n renderItem={({ item, index }) => (\n <GestureImage\n item={item}\n gesturesEnabled={index === currentImageIndex}\n scale={scale}\n translateX={translateX}\n translateY={translateY}\n dismissY={dismissY}\n opacity={opacity}\n />\n )}\n keyExtractor={(item, index) => `${item.id}-${index}`}\n horizontal\n pagingEnabled\n scrollEnabled={flatListScrollEnabled}\n showsHorizontalScrollIndicator={false}\n initialScrollIndex={initialImageIndex}\n getItemLayout={getItemLayout}\n onMomentumScrollEnd={onMomentumScrollEnd}\n onViewableItemsChanged={onViewableItemsChanged}\n viewabilityConfig={{\n itemVisiblePercentThreshold: 50, // 50% of the image must be visible in the window to be considered viewable\n }}\n style={styles.gallery}\n contentContainerStyle={styles.galleryContentContainer}\n />\n </GestureDetector>\n </GestureHandlerRootView>\n <LightboxToolbarHeader\n metaProps={metaProps}\n lightboxToolbarVisible={lightboxToolbarVisible}\n isStatusBarHidden={isStatusBarHidden}\n handleOpenInBrowser={handleOpenInBrowser}\n handleCloseModal={handleCloseModal}\n />\n {imageAttachments.length > 1 && (\n <LightboxToolbarFooter\n lightboxToolbarVisible={lightboxToolbarVisible}\n totalImages={imageAttachments.length}\n currentImageIndex={currentImageIndex}\n />\n )}\n </Modal>\n )\n}\n\ninterface GestureImageProps {\n item: DenormalizedMessageAttachmentResource\n gesturesEnabled: boolean\n scale: SharedValue<number>\n translateX: SharedValue<number>\n translateY: SharedValue<number>\n dismissY: SharedValue<number>\n opacity: SharedValue<number>\n}\n\nconst GestureImage = ({\n item,\n gesturesEnabled,\n scale,\n translateX,\n translateY,\n dismissY,\n opacity,\n}: GestureImageProps) => {\n const styles = useStyles()\n const { url: itemUrl, urlMedium: itemUrlMedium } = item.attributes\n\n const animatedImageStyles = useAnimatedStyle(() => {\n return {\n transform: [\n { translateX: gesturesEnabled ? translateX.value : DEFAULT_TRANSLATE_X },\n { translateY: gesturesEnabled ? translateY.value + dismissY.value : DEFAULT_TRANSLATE_Y },\n { scale: gesturesEnabled ? scale.value : DEFAULT_SCALE },\n ],\n opacity: opacity.value,\n }\n })\n\n return (\n <TouchEventIsolator>\n <Image\n source={{ uri: itemUrlMedium || itemUrl }}\n style={styles.gestureImage}\n animatedImageStyle={animatedImageStyles}\n loadingBackgroundStyles={styles.gestureImageLoading}\n resizeMode=\"contain\"\n alt=\"\"\n />\n </TouchEventIsolator>\n )\n}\n\nconst TouchEventIsolator = ({ children }: { children: React.ReactNode }) => {\n const styles = useStyles()\n\n return (\n <View style={styles.touchEventIsolator} onStartShouldSetResponder={() => true}>\n {children}\n </View>\n )\n}\n\ninterface LightboxToolbarHeaderProps {\n metaProps: MetaProps\n lightboxToolbarVisible: SharedValue<number>\n isStatusBarHidden: boolean\n handleOpenInBrowser: () => void\n handleCloseModal: () => void\n}\n\nconst LightboxToolbarHeader = ({\n metaProps,\n lightboxToolbarVisible,\n isStatusBarHidden,\n handleOpenInBrowser,\n handleCloseModal,\n}: LightboxToolbarHeaderProps) => {\n const styles = useStyles()\n const { authorName, createdAt } = metaProps\n\n const animatedHeaderStyles = useAnimatedStyle(() => ({\n opacity: lightboxToolbarVisible.value,\n transform: [\n { translateY: (1 - lightboxToolbarVisible.value) * -20 }, // slide up when hiding\n ],\n }))\n\n return (\n <Animated.View\n style={[styles.lightboxToolbar, styles.lightboxToolbarHeader, animatedHeaderStyles]}\n accessibilityRole=\"toolbar\"\n >\n <View style={styles.lightboxToolbarHeaderMetaContainer}>\n <Heading variant=\"h3\" style={styles.lightboxToolbarHeaderTitle} numberOfLines={1}>\n {authorName}\n </Heading>\n <Text variant=\"tertiary\" style={styles.lightboxToolbarHeaderSubtitle}>\n {formatDatePreview(createdAt)}\n </Text>\n </View>\n <IconButton\n onPress={handleOpenInBrowser}\n disabled={isStatusBarHidden}\n name=\"general.newWindow\"\n accessibilityRole=\"link\"\n accessibilityLabel=\"Open image in browser\"\n accessibilityHint=\"Image can be downloaded and shared through the browser.\"\n style={styles.lightboxToolbarButton}\n iconStyle={styles.lightboxToolbarButtonIcon}\n size=\"lg\"\n />\n <IconButton\n onPress={handleCloseModal}\n disabled={isStatusBarHidden}\n name=\"general.x\"\n accessibilityLabel=\"Close image\"\n style={styles.lightboxToolbarButton}\n iconStyle={styles.lightboxToolbarButtonIcon}\n size=\"lg\"\n />\n </Animated.View>\n )\n}\n\ninterface LightboxToolbarFooterProps {\n lightboxToolbarVisible: SharedValue<number>\n totalImages: number\n currentImageIndex: number\n}\n\nconst LightboxToolbarFooter = ({\n lightboxToolbarVisible,\n totalImages,\n currentImageIndex,\n}: LightboxToolbarFooterProps) => {\n const styles = useStyles()\n\n const animatedFooterStyles = useAnimatedStyle(() => ({\n opacity: lightboxToolbarVisible.value,\n transform: [\n { translateY: (1 - lightboxToolbarVisible.value) * 20 }, // slide down when showing\n ],\n }))\n\n return (\n <Animated.View\n style={[styles.lightboxToolbar, styles.lightboxToolbarFooter, animatedFooterStyles]}\n accessibilityRole=\"toolbar\"\n >\n <Text style={styles.lightboxToolbarFooterText}>\n {currentImageIndex + 1} of {totalImages}\n </Text>\n </Animated.View>\n )\n}\n\ninterface UseStylesProps {\n imageWidth?: number\n imageHeight?: number\n}\n\nconst useStyles = ({ imageWidth = 100, imageHeight = 100 }: UseStylesProps = {}) => {\n const { top, bottom } = useSafeAreaInsets()\n const backgroundColor = tokens.colorNeutral7\n const transparentBackgroundColor = useMemo(\n () => colorFunction(backgroundColor).alpha(0.8).toString(),\n [backgroundColor]\n )\n\n return StyleSheet.create({\n container: {\n maxWidth: '100%',\n },\n touchEventIsolator: {\n flex: 1,\n },\n attachmentImageWrapper: {\n width: '100%',\n minWidth: 200,\n aspectRatio: imageWidth / imageHeight,\n },\n image: {\n borderRadius: 8,\n },\n gallery: {\n backgroundColor,\n },\n galleryContentContainer: {\n paddingTop: top,\n paddingBottom: bottom,\n },\n gestureImage: {\n height: '100%',\n width: WINDOW_WIDTH,\n backgroundColor: 'transparent',\n },\n gestureImageLoading: {\n backgroundColor,\n },\n lightboxToolbar: {\n width: '100%',\n position: 'absolute',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 20,\n paddingHorizontal: 16,\n backgroundColor: transparentBackgroundColor,\n },\n lightboxToolbarButton: {\n backgroundColor,\n height: 40,\n width: 40,\n borderRadius: 50,\n borderWidth: 1,\n borderColor: tokens.colorNeutral24,\n },\n lightboxToolbarButtonIcon: {\n color: tokens.colorNeutral88,\n },\n lightboxToolbarHeader: {\n top: 0,\n paddingTop: top + 16,\n paddingBottom: 8,\n },\n lightboxToolbarHeaderMetaContainer: {\n flex: 1,\n },\n lightboxToolbarHeaderTitle: {\n marginRight: 'auto',\n flexShrink: 1,\n color: tokens.colorNeutral88,\n },\n lightboxToolbarHeaderSubtitle: {\n color: tokens.colorNeutral68,\n },\n lightboxToolbarFooter: {\n justifyContent: 'center',\n bottom: 0,\n paddingTop: 8,\n paddingBottom: bottom + 16,\n },\n lightboxToolbarFooterText: {\n color: tokens.colorNeutral88,\n fontWeight: platformFontWeightMedium,\n },\n })\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.12.0",
|
|
3
|
+
"version": "3.12.1-rc.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"prettier": "^3.4.2",
|
|
56
56
|
"typescript": "<5.6.0"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "0db64002a82e02c8adf5c9a1c1fcf174f9c59c8e"
|
|
59
59
|
}
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
NativeSyntheticEvent,
|
|
10
10
|
NativeScrollEvent,
|
|
11
11
|
ViewToken,
|
|
12
|
-
Platform,
|
|
13
12
|
} from 'react-native'
|
|
14
13
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
15
14
|
import {
|
|
@@ -17,7 +16,6 @@ import {
|
|
|
17
16
|
Gesture,
|
|
18
17
|
GestureDetector,
|
|
19
18
|
GestureHandlerRootView,
|
|
20
|
-
Pressable,
|
|
21
19
|
} from 'react-native-gesture-handler'
|
|
22
20
|
import Animated, {
|
|
23
21
|
runOnJS,
|
|
@@ -41,7 +39,6 @@ const { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window')
|
|
|
41
39
|
const DISMISS_PAN_THRESHOLD = 250
|
|
42
40
|
const MIN_DISTANCE_FOR_PAN = 10 // Higher threshold gives pinching priority
|
|
43
41
|
const SINGLE_FINGER_POINTER = 1 // Single-finger panning / tapping helps to avoid conflicts with pinching
|
|
44
|
-
const MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM = Platform.OS === 'ios' ? 8 : 0 // Causes taps to be unreliable on Android
|
|
45
42
|
const DEFAULT_OPACITY = 1
|
|
46
43
|
const DEFAULT_TRANSLATE_X = 0
|
|
47
44
|
const DEFAULT_TRANSLATE_Y = 0
|
|
@@ -423,9 +420,6 @@ const LightboxModal = ({
|
|
|
423
420
|
})
|
|
424
421
|
|
|
425
422
|
const doubleTapGesture = Gesture.Tap()
|
|
426
|
-
.maxDeltaX(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
427
|
-
.maxDeltaY(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
428
|
-
.maxDistance(MAX_TRAVEL_DISTANCE_FOR_DOUBLE_TAP_PLATFORM)
|
|
429
423
|
.minPointers(SINGLE_FINGER_POINTER)
|
|
430
424
|
.numberOfTaps(2)
|
|
431
425
|
.onStart(e => {
|
|
@@ -662,36 +656,34 @@ const LightboxModal = ({
|
|
|
662
656
|
/>
|
|
663
657
|
<GestureHandlerRootView>
|
|
664
658
|
<GestureDetector gesture={composedGesture}>
|
|
665
|
-
<
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
/>
|
|
694
|
-
</PreventPressEventsBubbling>
|
|
659
|
+
<FlatList
|
|
660
|
+
data={imageAttachments}
|
|
661
|
+
renderItem={({ item, index }) => (
|
|
662
|
+
<GestureImage
|
|
663
|
+
item={item}
|
|
664
|
+
gesturesEnabled={index === currentImageIndex}
|
|
665
|
+
scale={scale}
|
|
666
|
+
translateX={translateX}
|
|
667
|
+
translateY={translateY}
|
|
668
|
+
dismissY={dismissY}
|
|
669
|
+
opacity={opacity}
|
|
670
|
+
/>
|
|
671
|
+
)}
|
|
672
|
+
keyExtractor={(item, index) => `${item.id}-${index}`}
|
|
673
|
+
horizontal
|
|
674
|
+
pagingEnabled
|
|
675
|
+
scrollEnabled={flatListScrollEnabled}
|
|
676
|
+
showsHorizontalScrollIndicator={false}
|
|
677
|
+
initialScrollIndex={initialImageIndex}
|
|
678
|
+
getItemLayout={getItemLayout}
|
|
679
|
+
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
680
|
+
onViewableItemsChanged={onViewableItemsChanged}
|
|
681
|
+
viewabilityConfig={{
|
|
682
|
+
itemVisiblePercentThreshold: 50, // 50% of the image must be visible in the window to be considered viewable
|
|
683
|
+
}}
|
|
684
|
+
style={styles.gallery}
|
|
685
|
+
contentContainerStyle={styles.galleryContentContainer}
|
|
686
|
+
/>
|
|
695
687
|
</GestureDetector>
|
|
696
688
|
</GestureHandlerRootView>
|
|
697
689
|
<LightboxToolbarHeader
|
|
@@ -712,14 +704,6 @@ const LightboxModal = ({
|
|
|
712
704
|
)
|
|
713
705
|
}
|
|
714
706
|
|
|
715
|
-
const PreventPressEventsBubbling = ({ children }: { children: React.ReactNode }) => {
|
|
716
|
-
return (
|
|
717
|
-
<Pressable onLongPress={() => {}} onPress={() => {}}>
|
|
718
|
-
{children}
|
|
719
|
-
</Pressable>
|
|
720
|
-
)
|
|
721
|
-
}
|
|
722
|
-
|
|
723
707
|
interface GestureImageProps {
|
|
724
708
|
item: DenormalizedMessageAttachmentResource
|
|
725
709
|
gesturesEnabled: boolean
|
|
@@ -754,14 +738,26 @@ const GestureImage = ({
|
|
|
754
738
|
})
|
|
755
739
|
|
|
756
740
|
return (
|
|
757
|
-
<
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
741
|
+
<TouchEventIsolator>
|
|
742
|
+
<Image
|
|
743
|
+
source={{ uri: itemUrlMedium || itemUrl }}
|
|
744
|
+
style={styles.gestureImage}
|
|
745
|
+
animatedImageStyle={animatedImageStyles}
|
|
746
|
+
loadingBackgroundStyles={styles.gestureImageLoading}
|
|
747
|
+
resizeMode="contain"
|
|
748
|
+
alt=""
|
|
749
|
+
/>
|
|
750
|
+
</TouchEventIsolator>
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const TouchEventIsolator = ({ children }: { children: React.ReactNode }) => {
|
|
755
|
+
const styles = useStyles()
|
|
756
|
+
|
|
757
|
+
return (
|
|
758
|
+
<View style={styles.touchEventIsolator} onStartShouldSetResponder={() => true}>
|
|
759
|
+
{children}
|
|
760
|
+
</View>
|
|
765
761
|
)
|
|
766
762
|
}
|
|
767
763
|
|
|
@@ -876,6 +872,9 @@ const useStyles = ({ imageWidth = 100, imageHeight = 100 }: UseStylesProps = {})
|
|
|
876
872
|
container: {
|
|
877
873
|
maxWidth: '100%',
|
|
878
874
|
},
|
|
875
|
+
touchEventIsolator: {
|
|
876
|
+
flex: 1,
|
|
877
|
+
},
|
|
879
878
|
attachmentImageWrapper: {
|
|
880
879
|
width: '100%',
|
|
881
880
|
minWidth: 200,
|