diff --git a/native/chat/settings/thread-settings-media-gallery.react.js b/native/chat/settings/thread-settings-media-gallery.react.js --- a/native/chat/settings/thread-settings-media-gallery.react.js +++ b/native/chat/settings/thread-settings-media-gallery.react.js @@ -1,16 +1,26 @@ // @flow +import { useNavigation, useRoute } from '@react-navigation/native'; import * as React from 'react'; import { View, useWindowDimensions } from 'react-native'; +import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet'; import { FlatList } from 'react-native-gesture-handler'; import { fetchThreadMedia } from 'lib/actions/thread-actions.js'; -import type { MediaInfo } from 'lib/types/media-types'; +import type { MediaInfo, Media } from 'lib/types/media-types'; import { useServerCall } from 'lib/utils/action-utils.js'; import GestureTouchableOpacity from '../../components/gesture-touchable-opacity.react.js'; import Multimedia from '../../media/multimedia.react.js'; +import { + ImageModalRouteName, + VideoPlaybackModalRouteName, +} from '../../navigation/route-names.js'; import { useStyles } from '../../themes/colors.js'; +import type { + LayoutCoordinates, + VerticalBounds, +} from '../../types/layout-types.js'; const galleryItemGap = 8; const numColumns = 3; @@ -18,6 +28,7 @@ type ThreadSettingsMediaGalleryProps = { +threadID: string, +limit: number, + +verticalBounds: ?VerticalBounds, }; function ThreadSettingsMediaGallery( @@ -36,7 +47,7 @@ const galleryItemWidth = (width - 32 - (numColumns - 1) * galleryItemGap) / numColumns; - const { threadID, limit } = props; + const { threadID, limit, verticalBounds } = props; const [mediaInfos, setMediaInfos] = React.useState([]); const callFetchThreadMedia = useServerCall(fetchThreadMedia); @@ -73,30 +84,16 @@ }, [galleryItemWidth, styles.media, styles.mediaContainer]); const renderItem = React.useCallback( - ({ item, index }) => { - const containerStyle = - index % numColumns === 0 - ? memoizedStyles.mediaContainer - : memoizedStyles.mediaContainerWithMargin; - - const mediaInfoItem: MediaInfo = { - ...item, - index, - }; - - return ( - - - - - - ); - }, - [ - memoizedStyles.media, - memoizedStyles.mediaContainer, - memoizedStyles.mediaContainerWithMargin, - ], + ({ item, index }) => ( + + ), + [threadID, verticalBounds, memoizedStyles], ); return ( @@ -110,6 +107,76 @@ ); } +type MediaGalleryItemProps = { + +item: Media, + +index: number, + +memoizedStyles: { + +mediaContainer: ViewStyleProp, + +mediaContainerWithMargin: ViewStyleProp, + +media: ViewStyleProp, + }, + +threadID: string, + +verticalBounds: ?VerticalBounds, +}; + +function MediaGalleryItem(props: MediaGalleryItemProps): React.Node { + const navigation = useNavigation(); + const route = useRoute(); + const ref = React.useRef(null); + const onLayout = React.useCallback(() => {}, []); + const { threadID, verticalBounds, memoizedStyles, item, index } = props; + + const mediaInfo: MediaInfo = React.useMemo( + () => ({ + ...(item: Media), + index, + }), + [item, index], + ); + + const navigateToMedia = React.useCallback(() => { + ref.current?.measure((x, y, width, height, pageX, pageY) => { + const initialCoordinates: LayoutCoordinates = { + x: pageX, + y: pageY, + width, + height, + }; + + navigation.navigate<'VideoPlaybackModal' | 'ImageModal'>({ + name: + mediaInfo.type === 'video' + ? VideoPlaybackModalRouteName + : ImageModalRouteName, + key: `multimedia|${threadID}|${mediaInfo.id}`, + params: { + presentedFrom: route.key, + mediaInfo, + item, + initialCoordinates, + verticalBounds, + }, + }); + }); + }, [navigation, route, threadID, mediaInfo, item, verticalBounds]); + + const containerStyle = + index % numColumns === 0 + ? memoizedStyles.mediaContainer + : memoizedStyles.mediaContainerWithMargin; + + return ( + + + + + + ); +} + const unboundStyles = { flatListContainer: { paddingHorizontal: 16, diff --git a/native/chat/settings/thread-settings.react.js b/native/chat/settings/thread-settings.react.js --- a/native/chat/settings/thread-settings.react.js +++ b/native/chat/settings/thread-settings.react.js @@ -208,6 +208,7 @@ +key: string, +threadInfo: ThreadInfo, +limit: number, + +verticalBounds: ?VerticalBounds, } | { +itemType: 'promoteSidebar' | 'leaveThread' | 'deleteThread', @@ -635,7 +636,8 @@ mediaGalleryListDataSelector = createSelector( (propsAndState: PropsAndState) => propsAndState.threadInfo, - (threadInfo: ThreadInfo) => { + (propsAndState: PropsAndState) => propsAndState.verticalBounds, + (threadInfo: ThreadInfo, verticalBounds: ?VerticalBounds) => { const listData: ChatSettingsItem[] = []; const limit = 6; @@ -652,6 +654,7 @@ key: 'mediaGallery', threadInfo, limit, + verticalBounds, }); listData.push({ @@ -953,6 +956,7 @@ ); } else if (item.itemType === 'leaveThread') {