Changeset View
Changeset View
Standalone View
Standalone View
native/chat/settings/thread-settings-media-gallery.react.js
// @flow | // @flow | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { | import { View, useWindowDimensions } from 'react-native'; | ||||
View, | |||||
TouchableOpacity, | |||||
Image, | |||||
useWindowDimensions, | |||||
} from 'react-native'; | |||||
import { FlatList } from 'react-native-gesture-handler'; | import { FlatList } from 'react-native-gesture-handler'; | ||||
import { fetchThreadMedia } from 'lib/actions/thread-actions.js'; | |||||
import type { MediaInfo } 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 { useStyles } from '../../themes/colors.js'; | import { useStyles } from '../../themes/colors.js'; | ||||
const galleryItemGap = 8; | const galleryItemGap = 8; | ||||
const numColumns = 3; | const numColumns = 3; | ||||
function ThreadSettingsMediaGallery(): React.Node { | type ThreadSettingsMediaGalleryProps = { | ||||
+threadID: string, | |||||
+limit: number, | |||||
}; | |||||
function ThreadSettingsMediaGallery( | |||||
props: ThreadSettingsMediaGalleryProps, | |||||
): React.Node { | |||||
const styles = useStyles(unboundStyles); | const styles = useStyles(unboundStyles); | ||||
const { width } = useWindowDimensions(); | const { width } = useWindowDimensions(); | ||||
// Explanation of galleryItemWidth: | // Explanation of galleryItemWidth: | ||||
// The FlatList has a horizontal padding of 16px on each side, | // The FlatList has a horizontal padding of 16px on each side, | ||||
// and so the width of the actual FlatList is `width - 32px`. | // and so the width of the actual FlatList is `width - 32px`. | ||||
// With three columns, there will be two gaps in between the items, | // With three columns, there will be two gaps in between the items, | ||||
// so the width of each item (with the gaps) will be | // so the width of each item (with the gaps) will be | ||||
// (width - 32px - (numColumns-1) * galleryItemGap) / numColumns. | // (width - 32px - (numColumns-1) * galleryItemGap) / numColumns. | ||||
// E.g. 16px, media, galleryItemGap, media, galleryItemGap, media, 16px | // E.g. 16px, media, galleryItemGap, media, galleryItemGap, media, 16px | ||||
const galleryItemWidth = | const galleryItemWidth = | ||||
(width - 32 - (numColumns - 1) * galleryItemGap) / numColumns; | (width - 32 - (numColumns - 1) * galleryItemGap) / numColumns; | ||||
const mediaInfos = React.useMemo(() => [], []); | |||||
const { threadID, limit } = props; | |||||
const [mediaInfos, setMediaInfos] = React.useState([]); | |||||
const callFetchThreadMedia = useServerCall(fetchThreadMedia); | |||||
React.useEffect(() => { | |||||
const fetchData = async () => { | |||||
const result = await callFetchThreadMedia({ | |||||
threadID, | |||||
limit, | |||||
offset: 0, | |||||
}); | |||||
setMediaInfos(result.media); | |||||
}; | |||||
fetchData(); | |||||
}, [callFetchThreadMedia, threadID, limit]); | |||||
const memoizedStyles = React.useMemo(() => { | const memoizedStyles = React.useMemo(() => { | ||||
return { | return { | ||||
mediaContainer: { | mediaContainer: { | ||||
marginTop: galleryItemGap, | marginTop: galleryItemGap, | ||||
width: galleryItemWidth, | width: galleryItemWidth, | ||||
...styles.mediaContainer, | ...styles.mediaContainer, | ||||
}, | }, | ||||
Show All 12 Lines | ): React.Node { | ||||
const renderItem = React.useCallback( | const renderItem = React.useCallback( | ||||
({ item, index }) => { | ({ item, index }) => { | ||||
const containerStyle = | const containerStyle = | ||||
index % numColumns === 0 | index % numColumns === 0 | ||||
? memoizedStyles.mediaContainer | ? memoizedStyles.mediaContainer | ||||
: memoizedStyles.mediaContainerWithMargin; | : memoizedStyles.mediaContainerWithMargin; | ||||
const mediaInfoItem: MediaInfo = { | |||||
...item, | |||||
index, | |||||
}; | |||||
return ( | return ( | ||||
<View key={item.id} style={containerStyle}> | <View key={item.id} style={containerStyle}> | ||||
<TouchableOpacity> | <GestureTouchableOpacity style={memoizedStyles.media}> | ||||
<Image source={item.source} style={memoizedStyles.media} /> | <Multimedia mediaInfo={mediaInfoItem} spinnerColor="black" /> | ||||
</TouchableOpacity> | </GestureTouchableOpacity> | ||||
</View> | </View> | ||||
); | ); | ||||
}, | }, | ||||
[ | [ | ||||
memoizedStyles.media, | memoizedStyles.media, | ||||
memoizedStyles.mediaContainer, | memoizedStyles.mediaContainer, | ||||
memoizedStyles.mediaContainerWithMargin, | memoizedStyles.mediaContainerWithMargin, | ||||
], | ], | ||||
Show All 28 Lines |